home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / sos3-2.lha / src / agg / Mapping.c < prev    next >
C/C++ Source or Header  |  1992-01-23  |  116KB  |  2,769 lines

  1. /* --------------------------------------------------------------------------
  2.  * Copyright 1992 by Forschungszentrum Informatik (FZI)
  3.  *
  4.  * You can use and distribute this software under the terms of the licence
  5.  * you should have received along with this program.
  6.  * If not or if you want additional information, write to
  7.  * Forschungszentrum Informatik, "STONE", Haid-und-Neu-Strasse 10-14,
  8.  * D-7500 Karlsruhe 1, Germany.
  9.  * --------------------------------------------------------------------------
  10.  */
  11. // **************************************************************************
  12. // Module Mapping                   9/8/90                    Jochen Alt (ja)
  13. //                                                   modified : 24/10/91 (bs)
  14. //                                                   modified : 22/11/91 (ja)
  15. // **************************************************************************
  16. // implements methods of classes: Mapping, sos_Map_node
  17. // **************************************************************************
  18.  
  19. #include "agg_err.h"
  20. #include "trc_agg.h"
  21. #include "sys.h"
  22. #include "Mapping.h"
  23. #include "agg_sos.h"
  24.  
  25. // erweiterbares Hash-Verfahren mit leichten Modifikationen
  26. // Quelle : Datenbankhandbuch Seite 247
  27. // siehe externe Dokumentation
  28.  
  29. #define get_key_based_on_equal()  get_role1_based_on_equal()
  30. #define get_info_based_on_equal() get_role2_based_on_equal()
  31. #define set_key_based_on_equal(b)  set_role1_based_on_equal(b)
  32. #define set_info_based_on_equal(b) set_role2_based_on_equal(b)
  33.  
  34. inline int absolute(int d) { return (d>0)?d:-d; }
  35.  
  36. const sos_Offset NIL=0;
  37.  
  38. // Da psm direkt benutzt wird, wird ein Datentyp  benoetigt, der
  39. // anstelle der Objekte abgespeichert wird. Dies ist ein object_save_t,
  40. // der augenblicklich als sos_Typed_id definiert ist. Die beiden Operatoren,
  41. // die object_save_t in sos_Object und umgekehrt konvertieren, sind
  42. // make_object_save und make_Object
  43. // ************************************************************************** 
  44. object_save_t make_object_save (sos_Object o)
  45. // ************************************************************************** 
  46. // nimm das sos_Object o, bastle daraus ein object_save, und
  47. // liefere es in os zurueck
  48. {  sos_Typed_id  tpid = o.typed_id();
  49.    object_save_t os;
  50.    bcopy_from_sos_Typed_id(&tpid,&os);
  51.    return os;
  52.  
  53. // ************************************************************************** 
  54. sos_Object make_Object (object_save_t &os)
  55. // ************************************************************************** 
  56. // nimm den object_save os, mache daraus ein sos_Object und liefere es zurueck
  57. {  sos_Typed_id tpid;
  58.    bcopy_to_sos_Typed_id(&tpid,&os);
  59.    return sos_Object::make(tpid);
  60.  
  61. /*
  62. Abhaengig von sos_Bool:list_cursor gibt es zwei Versionen eines Mappings:
  63. 1. Version: list_cursor = FALSE
  64.    Die Cursoroperatoren sind nur auf einem statischen Mapping
  65.    definiert. Wird ein Objekt eingefuegt, so kan sich die Cursor-Reihenfolge
  66.    voellig veraendern. Damit ist ein sinnvoller Umgang mit Cursorn nur auf
  67.    einem sich nicht veraendernden Mapping moeglich. Sobald etwas eingefuegt 
  68.    oder geloescht wird, sind die Cursor zu schliessen und neu von vorne 
  69.    zu beginnen. Die Reihenfolge der Objekte ist durch die
  70.    Reihenfolge in der Hashtabelle definiert, also fuer den Benutzer rein
  71.    zufaellig. In dieser Version braucht ein Eintrag 36 Byte (= 2x sos_Object
  72.    und ein Hashwert a 4 byte)
  73. 2. Version : list_cursor = TRUE
  74.    Die Cursor-Operatoren koennen auch an einem dynamischen Mapping gleich-
  75.    zeitig ausgefuehrt werden. Die einzelnen Eintraege sind miteinander
  76.    doppelt verkettet, ein Einfuegen erfolgt am Anfang der Liste. Ein Eintrag
  77.    braucht damit 36+2x16 = 68 Byte (zusaetzlich ein Vorwaerts und ein 
  78.    Rueckwaertszeiger). Damit werden die Prozeduren remove_at, insert_before
  79.    und insert_after sinnvoll. In der Implementierung wird auf einer Seite
  80.    die struct-Komponente list, bestehend aus den beiden Verweisen 
  81.    zusaetzlich abgespeichert.
  82.  
  83. In Funktionen, die ein Objekt zurueckliefern sollen, jedoch keines zum Liefern 
  84. haben, wird my_no_object als Ruckgabeparameter von benutzt. Weiterhin dient 
  85. my_no_object als Ende-der-Liste Marke im ersten und letzten Element des 
  86. Mappings. Kurzum, my_no_object ist ein Mapping- lokales NO_OBJECT, und dient 
  87. dazu, das Einfuegen von NO_OBJECT zu ermoeglichen.  Stattdessen kann man eben 
  88. my_no_object nicht einfuegen. Faktisch wird my_no_object immer mit dem 
  89. augenblicklich benutzten Mapping initialisiert, so dass ein Mapping nicht in 
  90. sich selbst eingefuegt werden kann. Dieses wird entsprechend abgefangen.
  91. */
  92.  
  93. #define PAGE_SIZE(list_cursor) \
  94.    (list_cursor?page_size_with_list: page_size_without_list)
  95.  
  96. // max_page_entries = die maximale Anzahl an Eintraegen auf einer Seite
  97. #define MAX_PAGE_ENTRIES(list_cursor) \
  98.    (list_cursor? max_page_entries_with_list: max_page_entries_without_list)
  99.  
  100. // aus einer gegebenen Position in der Hashtabelle und der lokalen Tiefe
  101. // der zugehoerigen Seitenliste kann die erste Position in der Hashtabelle
  102. // berechnet werden, die auf diesselbe Seitenliste zeigt.
  103. #define FIRST_LINK(ht_pos,local_depth) \
  104.    ((LSHIFT(1,local_depth)-1) BITAND ht_pos)
  105.  
  106. /* ***********    Implementierung von sos_Map_node    *********************
  107. Ein sos_Map_node enthaelt nur die Komponente sos_Object:key_val, die 
  108. dasjenige Objekt angibt, auf das der Cursor augenblicklich zeigt. 
  109. Ein sos_Map_node ist eindeutig einem Cursor zugeordnet und liegt 
  110. in dessen Container. Ist der Cursor ungueltig, so ist die Komponente 
  111. Cursor->get_key_val() == NO_OBJECT, andernfalls zeigt sie auf einen 
  112. sos_Map_node. Also wird beim Starten auf einem Mapping mit Inhalt ein 
  113. sos_Map_node erzeugt und dem Cursor zugeordnet, beim Verlassen des 
  114. letzten gueltigen Elements wird der sos_Map_node wieder geloescht.
  115. */
  116.  
  117.  
  118. // ************************************************************************** 
  119. sos_Int hash_id (sos_Object o)
  120. // ************************************************************************** 
  121. // benutzt die Adresse des Objektes, um daraus eine Zahl zu basteln
  122.  
  123. // Offsets liegen  nur auf durch 8 teilbaren Addressen
  124. // => die ersten 3 Bit sind nutzlos, wird sie weg.
  125. // Ist das Objekt aber keine Klassen-Instanz, sondern 
  126. // ein externes Objekt (z.B. sos_Int,sos_Char),
  127. // so wird der Offset benutzt, indem der Wert steht.
  128. {  sos_Int h = o.offset();
  129.    if (o.container() != UNUSED_CONTAINER)
  130.       h = RSHIFT(h,3) BITXOR sos_Int(o.container());
  131.     
  132.    return h;
  133. } // ** hash_id **
  134.  
  135.  
  136. // ************************************************************************** 
  137. ht_entry_t read_ht_entry(sos_Container ct, 
  138.                          sos_Offset ht_offset, 
  139.                          sos_Int ht_pos)
  140. // ************************************************************************** 
  141. {  union {sos_Offset dummy;
  142.       char       mem [HT_ENTRY_SIZE];} u;
  143.    ct.read(ht_offset+ht_pos*HT_ENTRY_SIZE, HT_ENTRY_SIZE, &u);
  144.    ht_entry_t ht_entry;
  145.    bcopy_to_sos_Offset(&ht_entry.page_list_offset,&u.mem[0]);
  146.    bcopy_to_sos_Char(&ht_entry.local_depth, &u.mem[SOS_OFFSET_SIZE] );
  147.    return ht_entry;
  148. } // ** read_ht_entry **
  149.  
  150. // ************************************************************************** 
  151. void write_ht_entry(sos_Container ct, 
  152.                     sos_Offset ht_offset, 
  153.                     sos_Int ht_pos, 
  154.                     ht_entry_t ht_entry)
  155. // ************************************************************************** 
  156. {  union {sos_Offset dummy;
  157.       char       mem [HT_ENTRY_SIZE];} u;
  158.  
  159.    bcopy_from_sos_Offset(&ht_entry.page_list_offset, &u.mem[0]);
  160.    bcopy_from_sos_Char(&ht_entry.local_depth, &u.mem[SOS_OFFSET_SIZE]);
  161.    ct.write(ht_offset+ht_pos*HT_ENTRY_SIZE, HT_ENTRY_SIZE, &u);
  162. } // ** write_ht_entry **
  163.  
  164.  
  165. // ************************************************************************** 
  166. page_header_t  read_page_header(sos_Container ct, sos_Offset page_offset) 
  167. // ************************************************************************** 
  168. {  union {sos_Offset dummy;
  169.       char       mem [PAGE_HEADER_SIZE];} u;
  170.  
  171.    page_header_t page_header;
  172.    ct.read (page_offset, PAGE_HEADER_SIZE, &u);
  173.    bcopy_to_sos_Offset(&page_header.next_page, &u.mem[0]);
  174.    bcopy_to_sos_Char(&page_header.pages, &u.mem[SOS_OFFSET_SIZE]);
  175.    bcopy_to_sos_Char(&page_header.entries_on_last_page,
  176.              &u.mem[SOS_OFFSET_SIZE+CHAR_SIZE]);
  177.  
  178.    return page_header;
  179. } // ** read_page_header **
  180.  
  181. // ************************************************************************** 
  182. void write_page_header(sos_Container ct,
  183.                        sos_Offset page_offset, 
  184.                        page_header_t& page_header)
  185. // ************************************************************************** 
  186. {  union {sos_Offset dummy;
  187.       char       mem [PAGE_HEADER_SIZE];} u;
  188.  
  189.    bcopy_from_sos_Offset(&page_header.next_page,&u.mem[0]);
  190.    bcopy_from_sos_Char(&page_header.pages,&u.mem[SOS_OFFSET_SIZE]);
  191.    bcopy_from_sos_Char(&page_header.entries_on_last_page,
  192.                &u.mem[SOS_OFFSET_SIZE+CHAR_SIZE]);
  193.    ct.write (page_offset, PAGE_HEADER_SIZE, &u);
  194. } // ** write_page_header **
  195.  
  196.  
  197. /*
  198. Eine Seitenliste besteht aus einzelnen Seiten des Typs page_t, wobei 
  199. diese durch Vorwaertszeiger verkettet sind. Auf jeder Seite befindet sich 
  200. ein Seitenkopf mit den Angaben:
  201.  
  202.         sos_Char       pages; 
  203.            => Anzahl der Seiten in der Seitenliste
  204.         sos_Char       entries_on_last_page;
  205.            => Eintraege auf der letzten Seite, alle anderen Seite sind
  206.               voll, d.h. sie haben max_page_entries Eintraege. Diese Angabe
  207.               wird nur auf der ersten Seite verwaltet, auf den restlichen
  208.               Seiten ist entries_on_last_page undefiniert.
  209.         sos_Offset next_page;
  210.            => Verweis auf die naechste Seite, bei der letzten Seite 
  211.               undefiniert.
  212. */
  213.  
  214.  
  215. // ************************************************************************** 
  216. void destroy_page_list(sos_Bool      list_cursor,
  217.                        sos_Container ct, 
  218.                        sos_Offset    page_offset,
  219.                        sos_Int       no_of_pages)
  220. // ************************************************************************** 
  221. // deallokiere im Container ct die Seitenliste bestehend aus den
  222. // Typen page_t, wobei die erste zu deallokierende Seite auf page_offset 
  223. // liegt. Insgesamt sind no_of_pages Seiten  zu loeschen.
  224. {  sos_Offset act_page_offset = page_offset;
  225.    sos_Offset next_page_offset;
  226.    for (sos_Int i=1;i<=no_of_pages;i++)
  227.    {     // Lese zuerst naechsten Verweis, bevor die Seite deallokiert wird
  228.       page_header_t page_header = read_page_header(ct, act_page_offset);
  229.       next_page_offset = page_header.next_page;
  230.       
  231.       ct.deallocate(act_page_offset,PAGE_SIZE(list_cursor));
  232.       act_page_offset = next_page_offset;
  233.    } 
  234. } // ** destroy_page_list **
  235.  
  236.  
  237. // ************************************************************************** 
  238. void read_page( sos_Bool      list_cursor,
  239.                 sos_Container ct,
  240.                 sos_Offset    page_offset, 
  241.                 sos_Int       no_of_entries, 
  242.                 page_t&       page)
  243. // ************************************************************************** 
  244. // Lese Seite ab sos_Offset page_offset. Es werden no_of_entries
  245. // Eintraege eingelesen.
  246. {  err_assert((no_of_entries>=0 AND no_of_entries<=MAX_PAGE_ENTRIES(list_cursor)),
  247.       "Mapping:read_page_entry::internal Error");
  248.    page.page_header = read_page_header(ct,page_offset);
  249.    union {sos_Typed_id dummy;
  250.       char         mem [MAX_PAGE_SIZE];} u;
  251.    ct.read(page_offset+PAGE_HEADER_SIZE, no_of_entries*ENTRY_SIZE,&u);
  252.    char *ptr = u.mem;
  253.    for (int i = 0;i<no_of_entries;i++)
  254.    {  bcopy_to_sos_Typed_id(&page.entry[i].key,ptr);
  255.       ptr += SOS_TYPED_ID_SIZE;
  256.       bcopy_to_sos_Typed_id(&page.entry[i].info,ptr);
  257.       ptr += SOS_TYPED_ID_SIZE;
  258.       bcopy_to_sos_Int(&page.entry[i].hash_value,ptr);
  259.       ptr += INT_SIZE;
  260.    } 
  261.  
  262.    if (list_cursor)
  263.    {     // Lese die Vorgaenger und Nachfolger Verweise
  264.       ptr = u.mem;
  265.       ct.read(page_offset+add_list_pos, no_of_entries*LIST_SIZE, &u);
  266.       for (int i = 0; i < no_of_entries; i++)
  267.       {  bcopy_to_sos_Typed_id(&page.list[i].pred,ptr);
  268.          ptr += SOS_TYPED_ID_SIZE;
  269.          bcopy_to_sos_Typed_id(&page.list[i].succ,ptr);
  270.          ptr += SOS_TYPED_ID_SIZE;
  271.       } 
  272.    }
  273. } // ** read_page **
  274.  
  275. // ************************************************************************** 
  276. sos_Int read_page( sos_Bool      list_cursor,
  277.                    sos_Container ct,
  278.                    page_header_t first_page_header, 
  279.                    ht_entry_t    ht_entry, 
  280.                    sos_Int       page_no, 
  281.                    page_t&       page)
  282. // ************************************************************************** 
  283. // Lese die page_no.te Seite, auf die der Hashtabelleneintrag ht_entry
  284. // zeigt, wobei der Seitenkopf der ersten Seite schon unter 
  285. // first_page_header bekannt ist.
  286. {  sos_Offset page_offset = ht_entry.page_list_offset;
  287.    page.page_header = first_page_header;
  288.  
  289.       // Durchlaufe Seitenliste bis zur richtigen Seite
  290.    for (sos_Int no = 1; no < page_no; no++)
  291.    { if (no >1)
  292.          page.page_header = read_page_header(ct,page_offset);
  293.       page_offset =page.page_header.next_page;
  294.    } 
  295.    sos_Int entries = (page_no < first_page_header.pages)?
  296.                      MAX_PAGE_ENTRIES(list_cursor):
  297.                      first_page_header.entries_on_last_page;
  298.    read_page(list_cursor, ct, page_offset, entries, page);
  299.  
  300.    return entries;
  301. } // ** read_page **
  302.  
  303. // ************************************************************************** 
  304. void read_page_entry(sos_Bool      list_cursor,
  305.                      sos_Container ct,
  306.                      sos_Int       page_offset, 
  307.                      sos_Int       entry_no, 
  308.                      page_t&       page)
  309. // ************************************************************************** 
  310. // Lese auf der Seite auf page_offset den entry_no.ten Eintrag in page
  311. {  err_assert((entry_no>=0 AND entry_no<=MAX_PAGE_ENTRIES(list_cursor)),
  312.       "Mapping::read_page_entry::internal Error");
  313.    union {sos_Typed_id dummy;
  314.       char         mem[ENTRY_SIZE];} u; // note: ENTY_SIZE > LIST_SIZE
  315.  
  316.    ct.read( page_offset+PAGE_HEADER_SIZE+entry_no*ENTRY_SIZE,
  317.             ENTRY_SIZE,&u);
  318.    bcopy_to_sos_Typed_id(&page.entry[entry_no].key,&u.mem[0]);
  319.    bcopy_to_sos_Typed_id(&page.entry[entry_no].info,&u.mem[SOS_TYPED_ID_SIZE]);
  320.    bcopy_to_sos_Int(&page.entry[entry_no].hash_value,
  321.             &u.mem[SOS_TYPED_ID_SIZE+SOS_TYPED_ID_SIZE]);
  322.  
  323.    if (list_cursor)
  324.    {  ct.read( page_offset+add_list_pos+entry_no*LIST_SIZE,
  325.                LIST_SIZE,&u);
  326.       bcopy_to_sos_Typed_id(&page.list[entry_no].pred,&u.mem[0]);
  327.       bcopy_to_sos_Typed_id(&page.list[entry_no].succ,
  328.                             &u.mem[SOS_TYPED_ID_SIZE]);
  329.    }
  330. } // ** read_page_entry **
  331.  
  332. // ************************************************************************** 
  333. void write_page(sos_Bool      list_cursor,
  334.                 sos_Container ct, 
  335.                 sos_Offset    page_offset,
  336.                 sos_Int       no_of_entries, 
  337.                 page_t&       page)
  338. // ************************************************************************** 
  339. // Schreibe die Seite page mit no_of_entries Eintraegen 
  340. // an die Stelle page_offset
  341. {  write_page_header(ct,page_offset,page.page_header);
  342.    err_assert((no_of_entries>=0 AND no_of_entries<=MAX_PAGE_ENTRIES(list_cursor)),
  343.       "Mapping::write_page::internal Error");
  344.  
  345.    union {sos_Typed_id dummy;
  346.       char           mem [MAX_PAGE_SIZE];} u;
  347.    char *ptr = u.mem;
  348.    for (int i = 0; i < no_of_entries; i++)
  349.    {  bcopy_from_sos_Typed_id(&page.entry[i].key,ptr);
  350.       ptr += SOS_TYPED_ID_SIZE;
  351.       bcopy_from_sos_Typed_id(&page.entry[i].info,ptr);
  352.       ptr += SOS_TYPED_ID_SIZE;
  353.       bcopy_from_sos_Int(&page.entry[i].hash_value,ptr);
  354.       ptr += INT_SIZE;
  355.    } 
  356.    ct.write(page_offset+PAGE_HEADER_SIZE, no_of_entries*ENTRY_SIZE,&u);
  357.  
  358.    if (list_cursor)
  359.    {  ptr = u.mem;
  360.       for (int i = 0; i < no_of_entries; i++)
  361.       {  bcopy_from_sos_Typed_id(&page.list[i].pred,ptr);
  362.          ptr += SOS_TYPED_ID_SIZE;
  363.          bcopy_from_sos_Typed_id(&page.list[i].succ,ptr);
  364.          ptr += SOS_TYPED_ID_SIZE;
  365.       }
  366.       ct.write(page_offset+add_list_pos, LIST_SIZE*no_of_entries, &u);
  367.    }
  368. } // ** write_page **
  369.  
  370. // ************************************************************************** 
  371. void write_page_entry(sos_Bool      list_cursor,
  372.                       sos_Container ct, 
  373.                       sos_Int       page_offset, 
  374.                       sos_Int       entry_no, 
  375.                       page_t&       page)
  376. // ************************************************************************** 
  377. // Schreibe auf der Seite page den einzelnen Eintrag Nr entry_no
  378. // auf die Platte, der Seitenanfang beginnt bei page_offset.
  379. {  err_assert((entry_no>=0 AND entry_no<=MAX_PAGE_ENTRIES(list_cursor)),
  380.       "Mapping::write_page::internal Error");
  381.    union {sos_Typed_id dummy;
  382.       char         mem[ENTRY_SIZE];} u; // note: ENTY_SIZE > LIST_SIZE
  383.  
  384.    bcopy_from_sos_Typed_id(&page.entry[entry_no].key,&u.mem[0]);
  385.    bcopy_from_sos_Typed_id(&page.entry[entry_no].info,
  386.                            &u.mem[SOS_TYPED_ID_SIZE]);
  387.    bcopy_from_sos_Int(&page.entry[entry_no].hash_value,
  388.               &u.mem[SOS_TYPED_ID_SIZE+SOS_TYPED_ID_SIZE]);
  389.  
  390.    ct.write( page_offset+PAGE_HEADER_SIZE+entry_no*ENTRY_SIZE,
  391.              ENTRY_SIZE,&u);
  392.    if (list_cursor)
  393.    {  bcopy_from_sos_Typed_id(&page.list[entry_no].pred,&u.mem[0]);
  394.       bcopy_from_sos_Typed_id(&page.list[entry_no].succ,
  395.                               &u.mem[SOS_TYPED_ID_SIZE]);
  396.       ct.write( page_offset+add_list_pos+entry_no*LIST_SIZE, LIST_SIZE,&u);
  397.    }   
  398. } // ** write_page_entry **
  399.  
  400. // search_page_for_key__F8sos_BoolR6page_tiiG10sos_Object
  401. // ************************************************************************** 
  402. sos_Int search_page_for_key(sos_Bool     key_based_on_equal, 
  403.                             page_t&      page, 
  404.                             sos_Int      entries, 
  405.                             sos_Int      org_hash_value, 
  406.                             sos_Object   key)
  407. // ************************************************************************** 
  408. // durchsucht die Seite page mit entries Eintraegen nach dem sos_Object key,
  409. // das den Hashwert org_hash_value besitzt. Wird es gefunden, wird seine
  410. // Position in der Seite geliefert, ansonsten -1.
  411. {  T_PROC("search_page_for_key");
  412.    TT(agg_M, T_ENTER);
  413.  
  414.    sos_Bool found = FALSE;
  415.    for (sos_Int i=0;
  416.         ((i<entries) AND (NOT found));
  417.         i++)
  418.    {  if (page.entry[i].hash_value == org_hash_value)
  419.       {  sos_Object o = make_Object(page.entry[i].key);
  420.          if (agg_same_entity(o, key, key_based_on_equal, EQ_STRONG))
  421.          {  found = TRUE;
  422.             TT(agg_M, T_LEAVE);
  423.             return i;
  424.          }
  425.       }
  426.    } 
  427.  
  428.    TT(agg_M, T_LEAVE);
  429.    return -1;
  430. } // ** search_page_for_key **
  431.  
  432. // ************************************************************************** 
  433. sos_Offset new_page_list(sos_Container ct, sos_Bool list_cursor)
  434. // ************************************************************************** 
  435. // allokiere eine neue Seitenliste und liefere deren sos_Offset zurueck
  436. {  T_PROC("new_page_list");
  437.    TT(agg_L, T_ENTER);
  438.  
  439.    sos_Offset new_page_offset = ct.allocate(PAGE_SIZE(list_cursor));
  440.    page_header_t page_header;
  441.    page_header.entries_on_last_page = 0;
  442.    page_header.pages = 1;
  443.    write_page_header(ct,new_page_offset, page_header);
  444.  
  445.    TT(agg_L, T_LEAVE);
  446.    return new_page_offset;
  447. } // ** new_page_list **
  448.  
  449. // ************************************************************************** 
  450. void sos_Object_sos_Object_Mapping::write_succ_pred(
  451.                                       sos_Container ct,
  452.                                       sos_Bool      key_based_on_equal,
  453.                                       sos_Bool      list_cursor,
  454.                                       sos_Object    key, 
  455.                                       sos_Bool      write_succ, 
  456.                                       sos_Object    succ_pred)
  457. // ************************************************************************** 
  458. // Schreibe in den Vorgaeger bzw. Nachfolger von key succ_pred.
  459. // Ob Vor oder Nachgaenger ausgewaehlt wird, wird durch write_succ 
  460. // geregelt. write_succ == TRUE schreibt succ_pred in den 
  461. // Nachfolgerzeiger von key, ansonsten in den Vorgaengerzeiger von key.
  462. {  T_PROC("Mapping::write_succ_pred");
  463.    TT(agg_M, T_ENTER);
  464.    sos_Object my_no_object = self;
  465.    if (my_no_object == key)
  466.    {  TT(agg_M, T_LEAVE);
  467.       return;
  468.    }
  469.    
  470.    sos_Int org_hash_value = absolute((key_based_on_equal)?
  471.                                       key.hash_value():hash_id(key));
  472.    sos_Int ht_pos = org_hash_value MOD self.get_ht_entries();
  473.    ht_entry_t ht_entry = read_ht_entry(ct,self.get_ht_offset(),ht_pos);
  474.  
  475.    sos_Offset page_offset = ht_entry.page_list_offset;
  476.    page_header_t first_page_header = read_page_header(ct, page_offset);
  477.    sos_Int pages = first_page_header.pages;
  478.    sos_Int entries_on_last_page = first_page_header.entries_on_last_page;
  479.  
  480.    sos_Int pos = -1; // entspricht "nicht gefunden"
  481.    sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  482.    page_t page;
  483.    for (sos_Int page_no = 1;
  484.         (page_no<=pages) AND (pos == -1);
  485.         page_no++)
  486.    {  if (page_no == pages)
  487.      entries_on_page = entries_on_last_page;
  488.  
  489.       read_page(TRUE, ct, page_offset, entries_on_page, page);
  490.       sos_Int pos = search_page_for_key ( key_based_on_equal,page, 
  491.                                           entries_on_page,
  492.                                           org_hash_value, key );
  493.       if (pos == -1)
  494.          page_offset = page.page_header.next_page;
  495.       else
  496.       {     // Objekt gefunden
  497.          if (write_succ)
  498.             page.list[pos].succ = make_object_save(succ_pred);
  499.          else
  500.             page.list[pos].pred = make_object_save(succ_pred);
  501.          write_page_entry(TRUE, ct,page_offset,pos, page);
  502.       }
  503.    } 
  504.    TT(agg_M, T_LEAVE);
  505. } // ** Mapping::write_succ_pred **
  506.  
  507.  
  508. // ************************************************************************** 
  509. sos_Offset increase_page_list( sos_Bool       list_cursor,
  510.                                sos_Container  ct, 
  511.                                sos_Offset     first_page_offset,
  512.                                page_header_t& first_page_header,
  513.                                sos_Offset     last_page_offset)
  514. // ************************************************************************** 
  515. // Eine Seitenliste, die an der Stelle ht_pos an der Hashtabelle
  516. // angehaengt ist, wird um eine Seite erweitert. diese Seite wird
  517. // hinten angehaengt. Ein Verweis auf die bisher letzte Seite 
  518. {  T_PROC("increase_page_list");
  519.    TT(agg_M, T_ENTER);
  520.  
  521.    sos_Offset new_page_offset = ct.allocate(PAGE_SIZE(list_cursor));
  522.  
  523.       // Eigentlich sollte der Fall der Seitenlisten gaenzlich vermieden
  524.       // werden. Wird nun eine Seitenliste tatsaechlich ueber 126 Seiten
  525.       // gross, so ist entweder die Statistik fehlerhaft, oder es
  526.       // sind tatsaechlich mehr als 3225 Eintraege mit demselben Hashwert im
  527.       // Mapping. Diese Faelle fuehren zum Absturz, da die Variable, die die
  528.       // Seiten in einer Seitenliste zaehlt, ein char ist. Ansich ist eine
  529.       // solche Konstellation jedoch nicht vorstellbar.
  530.    if (first_page_header.pages >= 126)
  531.       err_raise(err_SYS, "statistical Error","Mapping:insert");
  532.  
  533.    first_page_header.pages++;
  534.    first_page_header.entries_on_last_page = 0;
  535.   
  536.       // Existierte bisher nur eine Seite ?
  537.    if (first_page_header.pages == 2)
  538.       first_page_header.next_page = new_page_offset;
  539.    else
  540.    {     // Es gab schon mehr als eine Seite, der erste Seitenheader und 
  541.          // der Header der bisher letzten Seite muss geschrieben werden
  542.       page_header_t last_page_header;
  543.       last_page_header.next_page = new_page_offset;
  544.       write_page_header(ct,last_page_offset, last_page_header);
  545.    }
  546.    write_page_header(ct,first_page_offset, first_page_header);
  547.  
  548.    TT(agg_M, T_LEAVE);
  549.    return new_page_offset;
  550. } // ** Mapping::increase_page_list
  551.  
  552. /*
  553. Um zu entscheiden, ob die Hashtabelle geschrumpft werden kann, muss bekannt 
  554. sein, ob es Seitenlisten gibt, auf die nur ein HT-Eintrag verweist. Falls ja,
  555. ist ein Schrumpfen nicht moeglich. Da beim Teilen und Splitten einer Seite
  556. die lokale Tiefe veraendert wird, muss fuer jede moegliche lokale Tiefe 
  557. die Anzahl der Verweise gespeichert werden, da beim Splitten 2 Seiten
  558. mit hoeheren lokalen Tiefen dazukommen und eine mit einer niedrigeren weg-
  559. faellt. 
  560. Es gibt also einen von Hand allokierten Platz, auf dessen Anfang 
  561. get_no_of_pages_offset() zeigt. In den ersten 4 Byte davon steht die Anzahl 
  562. der Seitenlisten mit lokaler Tiefe 0 , in den naechsten 4 Byte die Anzahl mit
  563. lokaler Tiefe 1 etc. bis MAX_GLOBAL_DEPTH.
  564. */
  565.  
  566. // ************************************************************************** 
  567. sos_Bool no_single_referenced_pages(sos_Container ct, 
  568.                                     sos_Offset    no_of_pages_offset, 
  569.                                     sos_Int       global_depth)
  570. // ************************************************************************** 
  571. // liefert TRUE, falls es keine Seitenliste gibt, die von der Hashtabelle
  572. // nur von einem einzigen Verweis referenziert wird. Dies wird anhand
  573. // der Zaehler festgestellt, die fuer jede lokale Tiefe zaehlen, wieviel
  574. // Seitenlisten es mit dieser lokalen Tiefe gibt. Die Seitenlisten,  die
  575. // nur von einem Verweis referenziert werden, zeichnen sich durch  
  576. // lokale Tiefe == globale Tiefe aus.
  577. {  sos_Int entry;
  578.    union {sos_Int dummy;
  579.       char    mem [INT_SIZE];} u;
  580.       // lese die Anzahl der Verweise auf Seitenlisten der lokalen 
  581.       // Tiefe global_depth
  582.    ct.read(no_of_pages_offset+INT_SIZE*global_depth,INT_SIZE,&u);
  583.    bcopy_to_sos_Int(&entry,&u); 
  584.    return sos_Bool (entry == 0);
  585. } // ** Mapping::no_single_referenced_pages **
  586.  
  587. // ************************************************************************** 
  588. void add_no_of_pages(sos_Container ct, 
  589.                      sos_Offset    no_of_pages_offset, 
  590.                      sos_Int       local_depth, 
  591.                      sos_Int       value)
  592. // ************************************************************************** 
  593. // zaehle zu der Anzahl von Verweisen auf eine Seitenliste mit der
  594. // lokalen Tiefe local_depth value dazu.
  595. {  sos_Int entry;
  596.    union {sos_Int dummy;
  597.       char    mem [INT_SIZE];} u;
  598.  
  599.    sos_Int offset = no_of_pages_offset+INT_SIZE*local_depth;
  600.    ct.read(offset, INT_SIZE, &u);
  601.    bcopy_to_sos_Int(&entry,&u);
  602.    entry += value;
  603.    bcopy_from_sos_Int(&entry,&u);
  604.    ct.write(offset, INT_SIZE, &u);
  605. } // ** add_no_of_page **
  606.  
  607.  
  608. // ************************************************************************** 
  609. void sos_Object_sos_Object_Mapping::insert_in_page_list (
  610.                                         sos_Container ct,
  611.                                         sos_Bool      key_based_on_equal,
  612.                                         sos_Bool      list_cursor,
  613.                                         sos_Offset    page_list_offset, 
  614.                                         sos_Int       org_hash_value, 
  615.                                         sos_Object key, sos_Object info,
  616.                                         sos_Object pred, sos_Object succ)
  617. // ************************************************************************** 
  618. // traegt einen Eintrag in eine Seitenliste ein und ersetzt
  619. // geg. einen alten. Auf der Seitenliste muss Platz sein
  620. {  T_PROC("Mapping::insert_in_page_list");
  621.  
  622.    page_t page;
  623.    sos_Offset page_offset = page_list_offset;
  624.    
  625.       // Befindet sich der key bereits auf der Seite, so wird er durch
  626.       // den neuen Eintrag ersetzt. Schaue also nach
  627.    
  628.    sos_Int pos = -1; // entspricht "nicht gefunden"
  629.    sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  630.  
  631.    page.page_header = read_page_header(ct,page_offset);
  632.  
  633.    page_header_t first_page_header = page.page_header;
  634.    sos_Int pages = first_page_header.pages;
  635.    sos_Int entries_on_last_page = first_page_header.entries_on_last_page;
  636.    for (sos_Int page_no=1; 
  637.         (page_no <= pages) AND (pos == -1); 
  638.         page_no++)
  639.    {  if (page_no == pages)
  640.      entries_on_page = entries_on_last_page;
  641.       read_page(list_cursor, ct,page_offset, entries_on_page, page);
  642.       pos = search_page_for_key (key_based_on_equal, page, 
  643.                                  entries_on_page, org_hash_value,key);
  644.       if ((pos == -1) AND (page_no < pages))
  645.          page_offset = page.page_header.next_page;
  646.    } 
  647.  
  648.       // Falls der Eintrag ersetzt wird, so wird er an diese
  649.       // Stelle eingesetzt. Ansonsten wird er auf der
  650.       // letzten Seite eingetragen und die H-Tabelle korrigiert
  651.  
  652.    sos_Int write_pos = pos;
  653.    if (pos == -1)
  654.    {     // Eintrag nicht gefunden, also schreibe ihn auf die letzte Seite.
  655.          // Da die gesamte Liste durchgegangen wurde, ist page_offset
  656.          // die Adresse der letzten Seite.
  657.       
  658.          // korrigiere Seitenheader der ersten Seite
  659.       first_page_header.entries_on_last_page++;
  660.       write_page_header(ct,page_list_offset,first_page_header);
  661.  
  662.       write_pos = entries_on_page;
  663.       self.set_cardinality(self.get_cardinality() + 1);
  664.    }
  665.  
  666.    page.entry[write_pos].hash_value = org_hash_value;
  667.       // Falls der Key existiert wird er nicht nochmal eingetragen,
  668.       // sondern nur der Entity ersetzt
  669.    if (write_pos != pos)
  670.       page.entry[write_pos].key = make_object_save(key);
  671.    page.entry[write_pos].info = make_object_save(info);
  672.  
  673.       // Schreibe die Liste evt auf die Seite zurueck
  674.    if (pos == -1)
  675.    {  if (list_cursor)
  676.       {     // schreibe in die Liste succ und pred
  677.          page.list[write_pos].succ = make_object_save(succ);
  678.          page.list[write_pos].pred = make_object_save(pred);
  679.             // aktualisiere den Vorwaertszeiger von pred und den 
  680.             // Rueckwaertszeiger von succ
  681.          self.write_succ_pred
  682.             (ct, key_based_on_equal, list_cursor, pred, TRUE, key);
  683.          self.write_succ_pred
  684.             (ct, key_based_on_equal, list_cursor, succ, FALSE, key);
  685.  
  686.          if (self.get_cardinality() == 1)
  687.          {     // erstes Element wird eingefuegt
  688.             self.set_first_object(key);
  689.             self.set_last_object(key);
  690.          }
  691.          else
  692.          {  if (self.get_first_object() == succ)
  693.                self.set_first_object(key);
  694.             if (self.get_last_object() == pred)
  695.                self.set_last_object(key);
  696.          }
  697.       }
  698.  
  699.          // schreibe den Eintrag auf der Seite zurueck
  700.       write_page_entry(list_cursor, ct,page_offset, write_pos, page);
  701.    }
  702.    else
  703.          // Der Eintrag war bereits vorhanden, nur der Entity wurde geaendert
  704.          // schreibe den Eintrag auf der Seite zurueck
  705.       write_page_entry(list_cursor, ct,page_offset, write_pos, page);
  706.  
  707.    TT(agg_M, T_LEAVE);
  708. } // ** Mapping::insert_in_page_list **
  709.  
  710.  
  711.  
  712. // ************************************************************************** 
  713. void sos_Object_sos_Object_Mapping::split_page(sos_Container ct, 
  714.                                                sos_Bool      list_cursor, 
  715.                                                sos_Offset    page_list_offset,
  716.                                                sos_Char      par_local_depth,
  717.                                                sos_Int       org_hash_value, 
  718.                                                sos_Int       nec_local_depth)
  719. // ************************************************************************** 
  720. // Eine Seitenliste wird solange gesplittet, bis der Seitenliste
  721. // die neue lokale Tiefe nec(cessary)_local_depth zugeordnet wird.
  722. // Saemtliche Seitenteilungen vor der letzten sind Seitenteilungen
  723. // ohne Bewegungen von Objekten, denn wuerden Objekte bewegt,
  724. // wuerde Platz geschaffen und somit waere nec_local_depth kleiner.
  725. {  T_PROC("Mapping::split_page");
  726.    TT(agg_M, T_ENTER);
  727.  
  728.    sos_Int global_depth = self.get_global_depth();
  729.    sos_Offset no_of_pages_offset = self.get_no_of_pages_offset();
  730.    sos_Offset ht_offset = self.get_ht_offset();
  731.  
  732.    sos_Int max_page_entries = MAX_PAGE_ENTRIES(list_cursor);
  733.       // Teile die Seitenliste sooft wie noetig, d.h. allokiere neue
  734.       // Seiten und biege die richtigen HT-Eintraege auf diese
  735.       // Seiten um
  736.    for (;par_local_depth <nec_local_depth;)
  737.    {     // erzeuge neue leere Seite
  738.       ht_entry_t new_ht_entry;
  739.       new_ht_entry.page_list_offset = new_page_list(ct, list_cursor);
  740.       sos_Int local_depth           = par_local_depth;
  741.       sos_Int new_local_depth       = ++par_local_depth;
  742.       new_ht_entry.local_depth      = new_local_depth;
  743.       self.set_no_of_page_lists(self.get_no_of_page_lists() + 1);
  744.       self.set_no_of_pages(self.get_no_of_pages() + 1);
  745.  
  746.       add_no_of_pages(ct,no_of_pages_offset,local_depth,-1);
  747.       add_no_of_pages(ct,no_of_pages_offset,new_local_depth,2);
  748.  
  749.          // biege alle Eintraege der HT mit gesetztem
  750.          // new_local_depth.ten Bit auf die neue Seite um
  751.  
  752.          // Wie lautet der der neuen Seite zugeordnete Hash-Wert-Teil ?
  753.          // Nimm den alten Hash-Teil
  754.       sos_Int old_hash_value_part = org_hash_value BITAND 
  755.                                     (LSHIFT(1,local_depth)-1); 
  756.  
  757.          // Laufe alle Indexe durch, bei denen ein Verweis
  758.          // auf die zu teilende Seitenliste steht. Das sind
  759.          // 2^(global_depth-local_depth) Stueck.
  760.  
  761.          // Die Verweise werden abwechselnd belassen und umgebogen.
  762.          // Da auf der alten Seitenliste die ersten nec_local_depth
  763.          // Bit gleich sind, wird so begonnen, dass die alte Seitenliste
  764.          // immer noch von der gleichen Stelle der 
  765.          // H-Tabelle erreicht wird (new_link)
  766.       sos_Bool new_link = FALSE; // starte bei alter Seitenliste
  767.       if ((org_hash_value BITAND LSHIFT(1,local_depth)) != 0)
  768.          new_link = TRUE; // starte bei leerer Seite
  769.  
  770.          // wo ist der erste Verweis auf diese Seitenliste ?
  771.       for (sos_Int k = 0;k<LSHIFT(1,global_depth-local_depth); k++)
  772.       {     // verschiebe Laufindex k an richtige Position 
  773.             // vor dem Wert der Seite
  774.          sos_Int j = LSHIFT(k,local_depth);
  775.             // addiere den Hash-Teil der Seite dazu
  776.          j = j BITOR old_hash_value_part;
  777.          
  778.          if (new_link)
  779.                // Dieser Eintrag muss auf die neue 
  780.                // leere Seite umgebogen werden
  781.             write_ht_entry(ct, ht_offset, j, new_ht_entry);
  782.          else
  783.          {     // Dieser Eintrag verbleibt,
  784.                // lediglich die lokale Tiefe wird geaendert
  785.             ht_entry_t tmp_ht_entry = read_ht_entry(ct, ht_offset, j);
  786.             tmp_ht_entry.local_depth ++;
  787.             write_ht_entry(ct,ht_offset,j, tmp_ht_entry);
  788.          }
  789.          new_link = (sos_Bool) (NOT new_link);
  790.       } 
  791.    } 
  792.  
  793.       // Da nur die letzte Seitenteilung hierbei beteiligt ist,
  794.       // muessen also Seiteneintraege der alten Seitenliste 
  795.       // auf die bis jetzt leere Partnerseite. 
  796.       // Berechne Hash-Teil der alten Seitenliste
  797.    sos_Int hash_value_part = org_hash_value BITAND 
  798.                              (LSHIFT(1,nec_local_depth)-1);
  799.       // invertiere das nec_local_depth.te Bit => Partnerseite 
  800.    sos_Int ht_partner_pos = hash_value_part BITXOR 
  801.                             LSHIFT(1,nec_local_depth-1);
  802.    
  803.       // Lese den Offset der Partnerseite
  804.    ht_entry_t ht_partner_entry = read_ht_entry(ct,ht_offset,ht_partner_pos);
  805.       // Also: Die Eintraege kommen von ht_entry.page_list_offset 
  806.       //       nach ht_partner_entry.page_list_offset
  807.  
  808.       // Gehe die alte Seitenliste durch und schiebe jeden Seiteneintrag,
  809.       // dessen Hashwert ein anderes nec_local_depth.tes Bit aufweist
  810.       // als in org_hash_value, auf die neue Seitenliste
  811.  
  812.    sos_Offset old_page_offset  = page_list_offset;
  813.    sos_Offset read_page_offset = old_page_offset;
  814.    sos_Offset new_page_offset  = ht_partner_entry.page_list_offset;
  815.    sos_Int bit                 = LSHIFT(1,nec_local_depth-1);
  816.    sos_Int should_be_bit       = org_hash_value BITAND bit;
  817.  
  818.    page_t old_page;
  819.    page_header_t old_page_header = read_page_header(ct,old_page_offset);
  820.    old_page.page_header =    old_page_header;
  821.    sos_Int old_entry_no     = 0;
  822.    sos_Int old_page_no      = 1;
  823.    sos_Bool add_old_page    = FALSE;
  824.  
  825.    page_t new_page;
  826.    sos_Int new_entry_no     = 0;
  827.    sos_Int new_page_no      = 1;
  828.  
  829.    page_header_t new_page_header = read_page_header(ct,new_page_offset);
  830.    new_page.page_header = new_page_header;
  831.  
  832.    page_t r_page;
  833.    page_header_t r_page_header = read_page_header(ct,read_page_offset);
  834.  
  835.    sos_Int no_of_pages = self.get_no_of_pages();
  836.    for (sos_Int read_page_no=1;
  837.         read_page_no <= r_page_header.pages;
  838.         read_page_no++)
  839.    {  sos_Int read_entries = (r_page_header.pages > read_page_no)?
  840.                           max_page_entries:r_page_header.entries_on_last_page;
  841.       read_page(list_cursor, ct,read_page_offset, read_entries, r_page);
  842.       read_page_offset = r_page.page_header.next_page;
  843.  
  844.          // Gehe die alte Seite durch und kopiere die passenden Eintraege
  845.          // auf die neue Seite. 
  846.       for (sos_Int read_no=0;read_no<read_entries;read_no++) 
  847.       {  if ((r_page.entry[read_no].hash_value BITAND bit) !=should_be_bit)
  848.             {     // gesetztes  Bit => Eintrag auf neue Seite
  849.  
  850.                   // Ist neue Seite schon vollstaendig beschrieben ?
  851.                if (new_entry_no == max_page_entries)
  852.                {     // Falls die neue Seite bereits voll ist, erweitere Liste
  853.                   sos_Offset last_page = 
  854.                      increase_page_list(list_cursor, ct, 
  855.                                         ht_partner_entry.page_list_offset,
  856.                                         new_page_header, new_page_offset);
  857.  
  858.                   no_of_pages++;
  859.                   new_page.page_header = new_page_header;
  860.                   new_page.page_header.next_page = last_page;
  861.  
  862.                      // und schreibe die volle Seite aus
  863.                   write_page(list_cursor, ct, new_page_offset, 
  864.                             max_page_entries, new_page);
  865.  
  866.                   new_entry_no = 0;
  867.                   new_page_offset = last_page;
  868.                   new_page_no++;
  869.  
  870.                }
  871.                new_page.entry[new_entry_no] = r_page.entry[read_no]; 
  872.                   // Falls list_cursor == FALSE schadet 
  873.                   // die folgende Zeile nichts
  874.                new_page.list[new_entry_no++] = r_page.list[read_no];
  875.             }
  876.          else
  877.             {     // Ist die alte Seite schon vollstaendig beschrieben ?
  878.                if (old_entry_no == max_page_entries)
  879.                {     // Ja, schreibe alte volle Seite aus
  880.                   write_page(list_cursor, ct,
  881.                              old_page_offset, max_page_entries, old_page);
  882.  
  883.                   old_page_no++;
  884.                   old_page_offset = old_page.page_header.next_page;
  885.  
  886.                      // Lese den Vorwaertsverweis der naechsten Seite
  887.                   if (old_page_no < old_page_header.pages)
  888.                     old_page.page_header=read_page_header(ct,old_page_offset);
  889.  
  890.                   old_entry_no = 0;
  891.                }
  892.                old_page.entry[old_entry_no] = r_page.entry[read_no];
  893.                   // Falls list_cursor == FALSE schadet 
  894.                   // die folgende Zeile nichts
  895.                old_page.list[old_entry_no++] = r_page.list[read_no];
  896.             }
  897.       } 
  898.    } 
  899.                   
  900.    self.set_no_of_pages(no_of_pages);
  901.  
  902.       // Falls eine neue Seite noch nicht ausgeschrieben ist, tue dies
  903.    if (new_entry_no > 0)
  904.    {  new_page.page_header.entries_on_last_page = new_entry_no;
  905.       new_page.page_header.pages = new_page_no;
  906.       write_page(list_cursor, ct,new_page_offset, new_entry_no, new_page);
  907.    }
  908.  
  909.       // Korrigiere Seitenheader der ersten neuen Seite
  910.    new_page_header.entries_on_last_page = new_entry_no;
  911.    new_page_header.pages = new_page_no;
  912.  
  913.       // Schreibe evt. den Seitenheader
  914.    if ((new_page_header.pages > 1) OR (new_entry_no == 0))
  915.       write_page_header(ct,ht_partner_entry.page_list_offset,new_page_header);
  916.  
  917.  
  918.       // Falls eine alte Seite noch nicht ausgeschrieben wurde, tue dies
  919.    if (old_entry_no > 0)
  920.    {  old_page.page_header.entries_on_last_page = old_entry_no;
  921.       old_page.page_header.pages = old_page_no;
  922.       write_page(list_cursor, ct,old_page_offset, old_entry_no, old_page);
  923.    }
  924.  
  925.       // Falls die alte Seitenliste eine volle Liste ist, lasse eine
  926.       // leere Seite dranhaengen, da auf der alten Seitenliste ein
  927.       // neuer Eintrag erfolgen soll.
  928.    if (old_entry_no == max_page_entries)
  929.    {  old_entry_no = 0;
  930.       old_page_no++;
  931.       add_old_page = TRUE;
  932.    }
  933.  
  934.       // Korrigiere Seitenheader der ersten alten Seite
  935.    old_page_header.entries_on_last_page = old_entry_no;
  936.    old_page_header.pages = old_page_no;
  937.  
  938.       // Schreibe evt. alten Seitenheader
  939.    if ((old_page_header.pages > 1) OR (old_entry_no == 0))
  940.       write_page_header(ct,page_list_offset, old_page_header);
  941.  
  942.       // Gebe den Rest der alten Seitenliste frei
  943.    if (old_page_no < r_page_header.pages) 
  944.    {  destroy_page_list(list_cursor, ct, old_page.page_header.next_page, 
  945.                         r_page_header.pages-old_page_no);
  946.       self.set_no_of_pages(no_of_pages - (r_page_header.pages - old_page_no));
  947.    }
  948.    TT(agg_M, T_LEAVE);
  949. } // ** Mapping::split_page **
  950.  
  951.  
  952. // ************************************************************************** 
  953. void sos_Object_sos_Object_Mapping::increase_hash_table()
  954. // ************************************************************************** 
  955. // erweitere die gesamte Hash-Tabelle, d.h. allokiere
  956. // doppelt soviel Platz wie jetzt belegt wird, kopiere
  957. // die alte Hash-Tabelle in die erste Haelfte und danach
  958. // in die zweite Haelfte. => Auf jede Seite
  959. // existieren zwei Verweise. Wirf die alte Hashtabelle weg
  960. {  T_PROC("Mapping::increase_hash_table");
  961.    TT(agg_M, T_ENTER);
  962.    sos_Container ct = self.container(); 
  963.    sos_Int old_ht_entries = self.get_ht_entries();
  964.    sos_Int old_ht_size = old_ht_entries*HT_ENTRY_SIZE;
  965.    sos_Offset new_ht_offset = ct.allocate(old_ht_size*2);
  966.  
  967.       // kopiere bisherige Hashtabelle zweimal 
  968.       // hintereinander in den neu allokierten Platz
  969.    ct.copy(self.get_ht_offset(), old_ht_size, ct, new_ht_offset);
  970.    ct.copy(self.get_ht_offset(), old_ht_size, ct, new_ht_offset+old_ht_size);
  971.  
  972.       // Wirf alte Hash-tabelle weg
  973.    ct.deallocate(self.get_ht_offset(), old_ht_size);
  974.  
  975.       // markiere die Neue
  976.    self.set_ht_offset(new_ht_offset);
  977.    self.set_ht_entries(old_ht_entries * 2);
  978.    self.set_global_depth(self.get_global_depth() + 1);
  979.    TT(agg_M, T_LEAVE);
  980. } // ** Mapping::increase_hash_table **
  981.  
  982. // increase_ht_structur__F8sos_Booliiiiii
  983. // ************************************************************************** 
  984. sos_Bool increase_ht_structur(sos_Bool list_cursor,
  985.                               sos_Int global_depth, 
  986.                               sos_Int ht_entries,
  987.                               sos_Int no_of_pages,
  988.                               sos_Int length,
  989.                               sos_Int local_depth, 
  990.                               sos_Int nec_local_depth)
  991. // ************************************************************************** 
  992. // entscheidet, ob wegen eines Seitenueberlaufs die HT-Struktur
  993. // vergoessert werden soll, oder an die Seitenliste eine Seite
  994. // angehaengt wird.
  995. {  
  996.    T_PROC("increase_ht_structur");
  997.    TT(agg_M, T_ENTER);
  998.  
  999.       // Falls die HT nicht vergroessert werden muesste, sondern 
  1000.       // eine Seitenteilung reichen wuerde, plaediere immer fuer die
  1001.       // Erweiterung der HT
  1002.    if (global_depth >= nec_local_depth)
  1003.    {  TT(agg_M, T_LEAVE)
  1004.       return TRUE;
  1005.    }
  1006.  
  1007.       // Berechne den Platzbedarf bei Vergroesserung der HT-Struktur
  1008.    sos_Int page_size = PAGE_SIZE(list_cursor);
  1009.    sos_Int ht_memory; // Bei HT-Erweiterung
  1010.    sos_Int pl_memory; // Bei Seitenlisten Erweiterung
  1011.    
  1012.       // Bei normaler  Speicherausnutzung, d.h. Jede Seite ist 
  1013.       // zur Haelfte gefuellt, gibt die Kennzahl 100, sonst > 100
  1014.       // Ist die Ausnutzung besser, gilt Kennzahl < 100
  1015.  
  1016.       // Bedarf der jetzigen Hashtabelle
  1017.    sos_Int ht_use = ht_entries*HT_ENTRY_SIZE;
  1018.   
  1019.       // Bedarf der jetzigen saemtlichen Seiten
  1020.    sos_Int page_lists_use = no_of_pages*page_size;
  1021.  
  1022.       // Berechne den Speicher, der beim Erweitern der HT-Struktur
  1023.       // zusaetzlich benoetigt wird
  1024.  
  1025.       // Fuer jedes Splitten kommt eine Seite dazu
  1026.    sos_Int increasing_use = (nec_local_depth-local_depth)*page_size;
  1027.       // Fuer das Erweitern der HT kommt immer die bisherige Groesse dazu
  1028.    increasing_use += (LSHIFT(1,nec_local_depth) - LSHIFT(1,global_depth))
  1029.                      *HT_ENTRY_SIZE;
  1030.  
  1031.    sos_Int ht_memory_used = ht_use + page_lists_use + increasing_use;
  1032.       // Bei der Alternative der Seitenliste kommt nur eine Seite dazu;
  1033.    sos_Int pl_memory_used = ht_use + page_lists_use + page_size;
  1034.  
  1035.       // Berechne den optimalen Platzbedarf. Er ergibt sich durch 
  1036.       // zu drei/viertel gefuellte Seiten, wobei jeder Verweis auf genau
  1037.       // eine Seite zeigt.=> Berechne Anzahl der noetigen Seiten = Verweise,
  1038.       // plumitiziere mit Platzbedarf
  1039.    sos_Int opt_entries = MAX_PAGE_ENTRIES(list_cursor)*3/4;
  1040.    sos_Int opt_memory_used = (page_size + HT_ENTRY_SIZE)*
  1041.                          length/opt_entries;
  1042.  
  1043.    ht_memory = (ht_memory_used*100) / opt_memory_used;
  1044.    pl_memory = (pl_memory_used*100) / opt_memory_used;
  1045.   
  1046.  
  1047.       // Berechne die Kennzahl der Zeiteffizienz 
  1048.       // Es wird die durchschnittliche Laenge einer Seitenliste berechnet
  1049.       // Falls keine Seitenlisten existieren, so ist die Effizienz
  1050.       // optimal. Die HT-Erweiterung ist in diesem Sinne optimal, auch wenn 
  1051.       // durch fruehere Seitenlisten die Effizienz nicht 1000 entspricht, 
  1052.       // ist der einzige moegliche Weg dorthin die HT-Erweiterung.
  1053.  
  1054.    sos_Int ht_eff = 100;
  1055.    sos_Int pl_eff = 100*(no_of_pages+1)/ht_entries;
  1056.  
  1057.  
  1058.       // Jetzt kommt die Entscheidung: Beide Kennzahlen
  1059.       // werden gleich gewichtet und verglichen
  1060.    sos_Bool result = FALSE;
  1061.    if ((ht_memory + ht_eff) <= (pl_memory + pl_eff))
  1062.       result = TRUE;
  1063.  
  1064.    TT(agg_M, T_LEAVE);
  1065.    return result;
  1066. } // ** Mapping::increase_ht_structur **
  1067.  
  1068.  
  1069. // ************************************************************************** 
  1070. sos_Int neccessary_local_depth(sos_Bool      list_cursor,
  1071.                                sos_Container ct, 
  1072.                                sos_Bool      key_based_on_equal,
  1073.                                sos_Offset    page_list_offset, 
  1074.                                sos_Char      local_depth,
  1075.                                sos_Offset&   last_page_offset,
  1076.                                sos_Int       org_hash_value, 
  1077.                                sos_Object    key)
  1078. // ************************************************************************** 
  1079. // Es wird berechnet, welche lokale Tiefe eine volle Seitenliste
  1080. // plus dem einzufuegenden Objekt haben muesste, damit mindestens 
  1081. // ein Seiten Eintrag abgespalten
  1082. // werden koennte. Oder: Es wird berechnet, bis zu welchem
  1083. // Bit im Hash-Wert nicht mehr alle Seiteneintraege gleich sind
  1084. // Wird dagegen ein Eintrag gefunden, der durch den neuen Eintrag
  1085. // ersetzt wuerde, so wird dieselbe lokale Tiefe zurueckgeliefert
  1086. {  T_PROC("neccessary_local_depth");
  1087.    TT(agg_M, T_ENTER);
  1088.  
  1089.    sos_Int hash_value = org_hash_value;
  1090.    sos_Int nec_local_depth = MAX_GLOBAL_DEPTH;
  1091.    sos_Offset page_offset = page_list_offset;
  1092.  
  1093.    page_header_t first_page_header;
  1094.    first_page_header = read_page_header(ct, page_list_offset);
  1095.    sos_Int pages = first_page_header.pages;
  1096.    sos_Int entries_on_last_page = first_page_header.entries_on_last_page;
  1097.    sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  1098.       // Durchlaufe alle Seiten
  1099.    for (sos_Int page_no=1; 
  1100.         (page_no<=pages);
  1101.         page_no++)
  1102.    {     // Diese Schleife darf nicht vorher abgebrochen werden, da
  1103.          // last_page_offset als Ausgabeparameter erwartet wird
  1104.  
  1105.       page_t page;
  1106.       if (page_no == pages) 
  1107.      entries_on_page = entries_on_last_page;
  1108.       read_page(list_cursor, ct, page_offset,entries_on_page, page);
  1109.  
  1110.       last_page_offset = page_offset;
  1111.       page_offset = page.page_header.next_page;
  1112.  
  1113.          // Durchlaufe alle Eintraege auf dieser Seite
  1114.       for (sos_Int entry_no = 0;
  1115.            (entry_no < entries_on_page);
  1116.            entry_no++)
  1117.       {  sos_Int tmp_hash_value = page.entry[entry_no].hash_value;
  1118.  
  1119.          if (org_hash_value == tmp_hash_value)
  1120.          {  sos_Object o = make_Object(page.entry[entry_no].key);
  1121.             if (agg_same_entity (key, o,key_based_on_equal, EQ_STRONG))
  1122.             {     // das Objekt wuerde dieses Objekt ersetzen, also
  1123.                // keine Erhoehung der lokalen Tiefe notwendig
  1124.            TT(agg_M, T_LEAVE);
  1125.                return local_depth;
  1126.             }
  1127.          }
  1128.             // Ab dem wievielten Bit unterscheiden sich der bisherige 
  1129.             // Hashwert und der aktuelle Eintrag ?
  1130.          sos_Int diff_hash_value = hash_value BITXOR tmp_hash_value;
  1131.  
  1132.             // Die Bits der lokalen Tiefe sind auf alle Faelle gleich,
  1133.             // also rechne erst ab local_depth+1; 
  1134.          for (sos_Int i = local_depth+1; 
  1135.               i<=nec_local_depth; 
  1136.               i++)
  1137.             if ((RSHIFT(diff_hash_value, i-1) BITAND 1) == 1)
  1138.                nec_local_depth = i++;
  1139.       } 
  1140.    } 
  1141.  
  1142.    TT(agg_M, T_LEAVE);
  1143.    return nec_local_depth;
  1144. } // ** Mapping::neccessary_local_depth *
  1145.  
  1146. // insert_in_list__30_sos_Object_sos_Object_MappingR12sos_Typed_idG10sos_ObjectN32
  1147. // ************************************************************************** 
  1148. void sos_Object_sos_Object_Mapping::insert_in_list
  1149.                                        (sos_Object key, sos_Object info, 
  1150.                                         sos_Object pred, sos_Object succ)
  1151. // ************************************************************************** 
  1152. // fuegt einen Eintrag ein und setzt ihn, falls list_cursor == TRUE
  1153. // in die durch pred und succ gegebenene Reihenfolge
  1154. {  T_PROC("Mapping::insert_in_list");
  1155.    TT(agg_M, T_ENTER);
  1156.  
  1157.       // Ist das Mapping leer, so existiert noch keine Hashtabelle
  1158.    if (self.get_ht_entries() == 0)
  1159.       self.init_table();
  1160.  
  1161.    sos_Container ct            = self.container();
  1162.    sos_Bool key_based_on_equal = self.get_key_based_on_equal();
  1163.    sos_Bool list_cursor        = self.get_list_cursor();
  1164.    sos_Int org_hash_value      = absolute((key_based_on_equal)?
  1165.                                           key.hash_value():hash_id(key));
  1166.    sos_Int ht_pos              = org_hash_value MOD self.get_ht_entries();
  1167.    sos_Offset ht_offset        = self.get_ht_offset();
  1168.    ht_entry_t ht_entry         = read_ht_entry(ct,ht_offset,ht_pos);
  1169.  
  1170.    page_header_t page_header   = read_page_header(ct,ht_entry.page_list_offset);
  1171.  
  1172.       // Ist die Seitenliste aufgefuellt ?
  1173.    if (page_header.entries_on_last_page < MAX_PAGE_ENTRIES(list_cursor))
  1174.          // Nein, es ist noch Platz
  1175.       self.insert_in_page_list(ct, key_based_on_equal, list_cursor,
  1176.                                 ht_entry.page_list_offset, org_hash_value, 
  1177.                                 key, info, pred, succ);
  1178.    else
  1179.    {     // Die Seitenliste ist voll. Entweder wird die HT erweitert,
  1180.          // oder die Seitenliste wird um eine Seite vergroessert.
  1181.       sos_Offset last_page =0;
  1182.       sos_Int nec_local_depth = 
  1183.           neccessary_local_depth( list_cursor, ct, key_based_on_equal, 
  1184.                                   ht_entry.page_list_offset, 
  1185.                                   ht_entry.local_depth,
  1186.                                   last_page, org_hash_value, key);
  1187.  
  1188.          // Falls der Eintrag einen anderen ersetzt, so 
  1189.          // ist keine Erweiterung notwendig
  1190.       if (nec_local_depth == ht_entry.local_depth)
  1191.          self.insert_in_page_list(ct, key_based_on_equal, list_cursor,
  1192.                                    ht_entry.page_list_offset, org_hash_value, 
  1193.                                    key, info, pred, succ);
  1194.       else
  1195.       {  if (increase_ht_structur
  1196.                (list_cursor,
  1197.                 self.get_global_depth(),self.get_ht_entries(),
  1198.                 self.get_no_of_pages(),self.get_cardinality(),
  1199.                 ht_entry.local_depth, nec_local_depth))
  1200.          {     // Die Hash-Struktur wird vergroessert, erweitere 
  1201.            // zuerst die Hashtabelle auf die benoetigten Groesse
  1202.             for (;self.get_global_depth() < nec_local_depth;)
  1203.                self.increase_hash_table(); // veraendert get_global_depth() !
  1204.                // Teile jetzt die Seiten. Hierbei sind alle Seitenteilungen
  1205.                // ohne Objektumschaufelungen verbunden, bis auf die letzte.
  1206.                // Drum der Parameter nec_local_depth
  1207.             self.split_page (ct, list_cursor,
  1208.                              ht_entry.page_list_offset, ht_entry.local_depth, 
  1209.                              org_hash_value, nec_local_depth);
  1210.    
  1211.             ht_pos = org_hash_value MOD self.get_ht_entries();
  1212.             ht_entry = read_ht_entry(ct,self.get_ht_offset(), ht_pos);
  1213.             self.insert_in_page_list (ct, key_based_on_equal, list_cursor,
  1214.                                       ht_entry.page_list_offset, 
  1215.                                       org_hash_value, key, info, 
  1216.                                       pred, succ);
  1217.          }
  1218.          else
  1219.          {     // Die Seitenliste wird um eine Seite erweitert:
  1220.             increase_page_list(list_cursor, ct, ht_entry.page_list_offset,
  1221.                                page_header, last_page);
  1222.             self.set_no_of_pages(self.get_no_of_pages()+1);
  1223.  
  1224.             self.insert_in_page_list(ct, key_based_on_equal, list_cursor,
  1225.                                      ht_entry.page_list_offset,org_hash_value,
  1226.                                      key, info, pred, succ);
  1227.          }
  1228.       }
  1229.    }
  1230.    TT (agg_M,T_LEAVE);
  1231. } // ** Mapping:insert_in_list **
  1232.  
  1233. // remove_from_page_list__30_sos_Object_sos_Object_MappingR12sos_Typed_idG13sos_Container8sos_BoolT3UiiG10sos_Object
  1234. // ************************************************************************** 
  1235. sos_Object sos_Object_sos_Object_Mapping::remove_from_page_list
  1236.                                            (sos_Container ct,
  1237.                                             sos_Bool      list_cursor,
  1238.                                             sos_Bool      key_based_on_equal,
  1239.                                             sos_Offset    page_list_offset,
  1240.                                             sos_Int       org_hash_value,
  1241.                                             sos_Object    key)
  1242. // ************************************************************************** 
  1243. // Liefert sos_Bool_Object::TRUE, falls der Eintrag gefunden wurde. Der Entry
  1244. // wird nicht geliefert, da er sonst mit make_Object angefasst werden muesste, 
  1245. // was er hier nicht soll.
  1246. {  T_PROC("Mapping::remove_from_page_list");
  1247.    TT(agg_M, T_ENTER);
  1248.  
  1249.    sos_Object my_no_object = self;
  1250.       // assume that key won't be found:
  1251.    sos_Object  found = make_sos_Bool_object(FALSE); 
  1252.    page_t page;
  1253.    page_header_t page_header;
  1254.    sos_Offset page_offset = page_list_offset;
  1255.    sos_Offset prev_page_offset;
  1256.    page_header = read_page_header(ct, page_offset);
  1257.    sos_Int pages = page_header.pages;
  1258.    sos_Int entries_on_last_page = page_header.entries_on_last_page;
  1259.    sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  1260.    sos_Int page_no = 1;
  1261.    sos_Int pos = -1; // entspricht "nicht gefunden";
  1262.    for (; (page_no<=pages) AND (pos == -1); page_no++)
  1263.    {  if (page_no == pages)
  1264.      entries_on_page = entries_on_last_page;
  1265.       read_page(list_cursor, ct, page_offset, entries_on_page, page);
  1266.       pos = search_page_for_key (key_based_on_equal, page, 
  1267.                                  entries_on_page, 
  1268.                                  org_hash_value,key);
  1269.       if (pos == -1)
  1270.       {  prev_page_offset  = page_offset;
  1271.          page_offset = page.page_header.next_page;
  1272.       }
  1273.    } 
  1274.    
  1275.    page_no --;
  1276.       // Im Falle von based_on_equal == TRUE ist der key nicht unbedingt 
  1277.       // derselbe wie der tatsaechlich eingetragene Schluessel. real_key
  1278.       // ist der Eingetragene. real_key ist fuer den Test auf Identitaet
  1279.       // mit dem ersten bzw. letzten Element notwendig.(Equal ginge auch,
  1280.       // dauert aber laenger).
  1281.    sos_Object real_key;  
  1282.  
  1283.    if (pos != -1)
  1284.    {  found = make_sos_Bool_object(TRUE);
  1285.       real_key = make_Object(page.entry[pos].key);
  1286.  
  1287.       sos_Object pred,succ;
  1288.       if (list_cursor)
  1289.       {  pred = make_Object(page.list[pos].pred);
  1290.          succ = make_Object(page.list[pos].succ);
  1291.       }
  1292.       self.set_cardinality(self.get_cardinality() - 1);
  1293.  
  1294.          // Der zu loeschende Eintrag ist auf der letzten Seite 
  1295.       if (page_no == page_header.pages)
  1296.       {     // fuelle die Luecke auf
  1297.          if (page_header.entries_on_last_page > 1)
  1298.          {     // und korrigiere den Seitenheader
  1299.             page.entry[pos] = page.entry[--page_header.entries_on_last_page];
  1300.             page.list[pos]  = page.list[page_header.entries_on_last_page];
  1301.                // schreibe Seiteneintrag zurueck
  1302.             write_page_entry(list_cursor, ct, page_offset, pos, page);
  1303.          }
  1304.          else
  1305.             // oder deallokiere die Seite
  1306.          {  if (page_header.pages > 1)
  1307.             {  ct.deallocate(page_offset, PAGE_SIZE(list_cursor));
  1308.                page_header.pages --;
  1309.                page_header.entries_on_last_page=MAX_PAGE_ENTRIES(list_cursor);
  1310.                self.set_no_of_pages(self.get_no_of_pages()-1);
  1311.             }
  1312.             else
  1313.                page_header.entries_on_last_page = 0;
  1314.         }
  1315.             // schreibe Seitenheader zurueck
  1316.          write_page_header(ct,page_list_offset, page_header);
  1317.       }
  1318.       else
  1319.       {     // Falls der Eintrag nicht auf der letzten Seite war, so nimm
  1320.             // einen Eintrag der letzten Seite und schreibe ihn in die Luecke
  1321.             // hangel dich zur letzten Seite vor
  1322.          sos_Offset last_page_offset = page.page_header.next_page;
  1323.          page_header_t tmp_page_header;
  1324.          page_no++;
  1325.          for (;page_no<page_header.pages;page_no++)
  1326.          {  tmp_page_header = read_page_header(ct, last_page_offset);
  1327.             last_page_offset = tmp_page_header.next_page;
  1328.          } 
  1329.  
  1330.             // nimm von der letzten Seite den letzten Eintrag
  1331.             // und korrigiere nur den Seitenheader
  1332.          page_t tmp_page;
  1333.          read_page_entry(list_cursor, ct,last_page_offset, 
  1334.                          --page_header.entries_on_last_page,
  1335.                          tmp_page);
  1336.  
  1337.             // und fuege ihn in die Luecke
  1338.          page.entry[pos] = tmp_page.entry[page_header.entries_on_last_page];
  1339.          page.list[pos]  = tmp_page.list[page_header.entries_on_last_page];
  1340.  
  1341.          write_page(list_cursor, ct,page_offset, pos+1, page);
  1342.  
  1343.             // Falls die letzte Seite jetzt leer ist, deallokiere
  1344.          if (page_header.entries_on_last_page == 0)
  1345.          {  ct.deallocate(last_page_offset, PAGE_SIZE(list_cursor));
  1346.             page_header.entries_on_last_page = MAX_PAGE_ENTRIES(list_cursor);
  1347.             page_header.pages--;
  1348.             self.set_no_of_pages(self.get_no_of_pages()-1);
  1349.          }
  1350.  
  1351.             // Schreibe den Seitenheader der ersten Seite zurueck
  1352.          write_page_header(ct,page_list_offset, page_header);
  1353.       }
  1354.      
  1355.       if (list_cursor)
  1356.       {     // fuege Objekt aus der Liste
  1357.          self.write_succ_pred
  1358.             (ct, key_based_on_equal, list_cursor, pred, TRUE, succ);
  1359.          self.write_succ_pred
  1360.             (ct, key_based_on_equal, list_cursor, succ, FALSE, pred);
  1361.       
  1362.          if (real_key == self.get_last_object())
  1363.             self.set_last_object(pred);
  1364.          if (real_key == self.get_first_object())
  1365.             self.set_first_object(succ);
  1366.             
  1367.             // Letztes Objekt:
  1368.          if (self.get_cardinality() == 0)
  1369.          {  sos_Object my_no_object = self;
  1370.             self.set_first_object(my_no_object);
  1371.             self.set_last_object(my_no_object);
  1372.          }
  1373.       }
  1374.    } 
  1375.  
  1376.    TT(agg_M, T_LEAVE);
  1377.    return found;
  1378. } // ** Mapping::remove_from_page_list **
  1379.  
  1380.  
  1381.  
  1382. // ************************************************************************** 
  1383. sos_Bool sos_Object_sos_Object_Mapping::assemble_page(
  1384.                                            sos_Offset page_list_offset,
  1385.                                            sos_Char   local_depth,
  1386.                                            sos_Int    org_hash_value)
  1387. // ************************************************************************** 
  1388. {  T_PROC("Mapping::assemble_page");
  1389.    TT(agg_M, T_ENTER);
  1390.  
  1391.    sos_Container ct         = self.container(); 
  1392.    sos_Bool list_cursor     = self.get_list_cursor();
  1393.    sos_Int max_page_entries = MAX_PAGE_ENTRIES(list_cursor);
  1394.  
  1395.    page_t page;
  1396.    page_t partner_page;
  1397.    ht_entry_t ht_partner_entry;
  1398.  
  1399.    page.page_header     = read_page_header(ct, page_list_offset);
  1400.    sos_Int ht_partner_pos;
  1401.  
  1402.    sos_Bool assemble_flag;
  1403.       // liefere zurueck, ob verschmolzen wurde
  1404.    sos_Bool result             = FALSE; 
  1405.    sos_Bool act_page_is_read   = FALSE;
  1406.  
  1407.    do // while (assemble_flag)
  1408.    {  assemble_flag = FALSE;
  1409.  
  1410.          // zuerst eine Grob-Pruefung, ob eine Chance auf 
  1411.          // Verschmelzung besteht:
  1412.          // Ist die Seitenliste nur eine Seite, und ist sie nur 3/4 voll,
  1413.          // und gibt es ueberhaupt eine Partnerseite ?
  1414.       if ((page.page_header.entries_on_last_page <= max_page_entries*3/4) AND
  1415.           (page.page_header.pages == 1) AND
  1416.           (local_depth > 0))
  1417.       {     // Berechne die Position der Partnerseite
  1418.          ht_partner_pos     = (org_hash_value BITAND LSHIFT(1,local_depth)-1)
  1419.                               BITXOR LSHIFT(1,local_depth-1);
  1420.  
  1421.             // Lese den HT-Eintrag der Partnerseite
  1422.          ht_partner_entry =
  1423.             read_ht_entry(ct,self.get_ht_offset(),ht_partner_pos);
  1424.          
  1425.             // Hat die Partnerseite die gleiche lokale Tiefe ?
  1426.          if (ht_partner_entry.local_depth == local_depth)
  1427.          {     // Ja
  1428.                // Lese Seitenkopf der Partner Seite
  1429.             partner_page.page_header = 
  1430.                    read_page_header(ct, ht_partner_entry.page_list_offset);
  1431.             
  1432.                // Besteht die Partnerseite auch nur aus einer Seite ?
  1433.             if (partner_page.page_header.pages == 1)
  1434.             {  // passen alle Eintraege gut auf eine Seite ? (gut = 25% frei)
  1435.                assemble_flag = FALSE;
  1436.                if ((partner_page.page_header.entries_on_last_page+
  1437.                      page.page_header.entries_on_last_page)
  1438.                      <= max_page_entries*3/4)
  1439.                   assemble_flag = TRUE;
  1440.             }
  1441.          } 
  1442.       }
  1443.  
  1444.       if (assemble_flag) 
  1445.       {  result = TRUE;
  1446.  
  1447.          self.set_no_of_page_lists(self.get_no_of_page_lists() - 1);
  1448.  
  1449.          if (NOT (act_page_is_read))
  1450.          {  read_page(list_cursor, ct,page_list_offset, 
  1451.                       page.page_header.entries_on_last_page, page);
  1452.             act_page_is_read = TRUE;
  1453.          }
  1454.  
  1455.             // Lese Partner-Seite
  1456.          read_page(list_cursor, ct,ht_partner_entry.page_list_offset, 
  1457.                    partner_page.page_header.entries_on_last_page, 
  1458.                    partner_page);
  1459.  
  1460.             // Kopiere die Eintraege der Partnerseite 
  1461.             // auf die urspruengliche Seite
  1462.          for (sos_Int i=0; i<partner_page.page_header.entries_on_last_page;i++)
  1463.          {  page.entry[page.page_header.entries_on_last_page] = 
  1464.                partner_page.entry[i];
  1465.             page.list[page.page_header.entries_on_last_page++] = 
  1466.                partner_page.list[i];
  1467.          } 
  1468.  
  1469.             // Korrigiere die Angabe, wieviel Seiten mit einer 
  1470.             // bestimmten lokalen Tiefe existieren
  1471.          sos_Int no_of_pages_offset = self.get_no_of_pages_offset();
  1472.          add_no_of_pages(ct,no_of_pages_offset,local_depth,-2);
  1473.          add_no_of_pages(ct,no_of_pages_offset,local_depth-1,1);
  1474.  
  1475.             // Gib die Partnerseite frei
  1476.          ct.deallocate (ht_partner_entry.page_list_offset, 
  1477.                         PAGE_SIZE(list_cursor));
  1478.          self.set_no_of_pages(self.get_no_of_pages()-1);
  1479.  
  1480.          write_page(list_cursor, ct,page_list_offset, 
  1481.                     page.page_header.entries_on_last_page, page);
  1482.        
  1483.          sos_Int old_local_depth = local_depth --;
  1484.  
  1485.             // Die Hashtabelle muss korrigiert werden: Alle
  1486.             // Verweise auf die Partnerseite muessen auf die verschmolzene
  1487.             // Seite umgebogen werden
  1488.             // Wie lautet der der vereinigten Seite zugeordnete Hashwertteil ? 
  1489.          sos_Int hash_value_part = ht_partner_pos BITAND 
  1490.                                (LSHIFT(1,local_depth)-1);
  1491.  
  1492.             // Laufe alle Indexe durch, die auf die neue
  1493.             // vereinigte Seite zeigen. Diese Verweise werden
  1494.             // umgebogen
  1495.          sos_Int global_depth = self.get_global_depth();
  1496.          sos_Offset ht_offset = self.get_ht_offset();
  1497.          for (sos_Int k = 0;k<LSHIFT(1,global_depth-local_depth); k++)
  1498.          {     // verschiebe Laufindex k an richtige Position 
  1499.                // vor dem Wert der Seite
  1500.             sos_Int j = LSHIFT(k,local_depth);
  1501.                // addiere hash-Teil der Seite dazu
  1502.             j = j BITOR hash_value_part;
  1503.             
  1504.                // Dieser Eintrag muss auf die neue Seite umgebogen werden
  1505.                // d.h. vielleicht zeigt er schon auf die Seite, aber
  1506.                // die lokale Tiefe ist in jedem Fall zu hoch
  1507.             ht_entry_t ht_entry;
  1508.             ht_entry.page_list_offset = page_list_offset;
  1509.             ht_entry.local_depth = local_depth;
  1510.             write_ht_entry(ct,ht_offset,j, ht_entry);
  1511.          }
  1512.       }
  1513.    } 
  1514.    while (assemble_flag);
  1515.  
  1516.    TT(agg_M,T_LEAVE);
  1517.    return result;
  1518. } // ** Mapping::assemble_page **
  1519.  
  1520.  
  1521. // ************************************************************************** 
  1522. void sos_Object_sos_Object_Mapping::decrease_hash_table()
  1523. // ************************************************************************** 
  1524. // die Hash-tabelle kann genau dann halbiert werden, wenn
  1525. // keine Seiten existieren, die nur einen Verweis in der 
  1526. // Hash-Tabelle besitzen
  1527. {  
  1528.    T_PROC("Mapping::decrease_hash_table");
  1529.    TT(agg_M, T_ENTER);
  1530.  
  1531.    sos_Container ct              = self.container(); 
  1532.    sos_Int global_depth          = self.get_global_depth();
  1533.    sos_Offset no_of_pages_offset = self.get_no_of_pages_offset();
  1534.  
  1535.    for (;no_single_referenced_pages(ct,no_of_pages_offset,global_depth);)
  1536.    {     // Merke alte Tabellen-Position und Laenge
  1537.       sos_Int old_ht_entries   = self.get_ht_entries();
  1538.       sos_Int old_ht_size      = old_ht_entries*HT_ENTRY_SIZE;
  1539.       sos_Offset old_ht_offset = self.get_ht_offset();
  1540.  
  1541.          // definiere neue Tabellen Position und Laenge
  1542.       sos_Int new_ht_entries = old_ht_entries / 2;
  1543.       sos_Int new_ht_size   = new_ht_entries*HT_ENTRY_SIZE;
  1544.       sos_Int new_ht_offset = ct.allocate(new_ht_entries*HT_ENTRY_SIZE);
  1545.       self.set_ht_entries(new_ht_entries);
  1546.       self.set_ht_offset(new_ht_offset);
  1547.  
  1548.          // kopiere erste Haelfte der alten Tabelle in neue Tabelle
  1549.       ct.copy( old_ht_offset,new_ht_size,ct,new_ht_offset); 
  1550.       global_depth--;
  1551.       
  1552.          // Gib alte Tabelle frei
  1553.       ct.deallocate(old_ht_offset,old_ht_size);
  1554.    }
  1555.    self.set_global_depth(global_depth);
  1556.    TT (agg_M,T_LEAVE); 
  1557. } // ** decrease_hash_table
  1558.  
  1559. // ************************************************************************** 
  1560. sos_Bool get_entry (sos_Container  ct, 
  1561.                     sos_Bool       list_cursor,
  1562.                     sos_Bool       key_based_on_equal, 
  1563.                     sos_Int        ht_entries,
  1564.                     sos_Offset     ht_offset,
  1565.                     sos_Object&    key,
  1566.             sos_Bool       return_info,
  1567.             sos_Object&    info,
  1568.                     sos_Object&    pred,
  1569.                     sos_Object&    succ)
  1570. // ************************************************************************** 
  1571. // Setzt key und - falls list_cursor == TRUE - pred und succ auf die
  1572. // key-Objekte im gegebenen Mapping. Ergebnis ist das dem key entsprechende
  1573. // info. Es gilt agg_same_entity (key-vorher, key-nachher, key_based_on_equal)
  1574. // Wird return_info== TRUE uebergeben, wird info geliefert, ansonsten nicht.
  1575. // pred und succ werden nur im Falle von list_cursor == TRUE geliefert.
  1576.     
  1577. {  T_PROC("get_entry");
  1578.    TT(agg_M,T_ENTER; TI(ht_entries); TI(ht_offset));
  1579.  
  1580.    if (ht_entries>0)
  1581.    {  sos_Int org_hash_value  = absolute((key_based_on_equal)?
  1582.                                          key.hash_value() : hash_id(key));
  1583.       sos_Int ht_pos          = org_hash_value MOD ht_entries;
  1584.       ht_entry_t ht_entry     = read_ht_entry(ct,ht_offset,ht_pos);
  1585.       page_t page;
  1586.  
  1587.       sos_Offset page_offset  = ht_entry.page_list_offset;
  1588.       sos_Int pos = -1; // entspricht "nicht gefunden"
  1589.  
  1590.       page_header_t page_header = read_page_header (ct, page_offset);
  1591.       sos_Int pages = page_header.pages;
  1592.       sos_Int entries_on_last_page = page_header.entries_on_last_page;
  1593.       sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  1594.       for (sos_Int page_no = 1; (page_no<=pages) AND (pos == -1); page_no++)
  1595.       {  if (page_no == pages)
  1596.         entries_on_page = entries_on_last_page;
  1597.          
  1598.          read_page(list_cursor, ct, page_offset, entries_on_page, page);
  1599.          pos = search_page_for_key ( key_based_on_equal, page, entries_on_page,
  1600.                                      org_hash_value, key );
  1601.          if (pos == -1)
  1602.             page_offset = page.page_header.next_page;
  1603.          else
  1604.          {  if (list_cursor)
  1605.             {  pred = make_Object(page.list[pos].pred);
  1606.                succ = make_Object(page.list[pos].succ);
  1607.            sos_Bool test1 = (succ == NO_OBJECT);
  1608.            sos_Bool test2 = (pred == NO_OBJECT);
  1609.             }
  1610.             key = make_Object(page.entry[pos].key);
  1611.             if (return_info)
  1612.            info = make_Object(page.entry[pos].info);
  1613.          
  1614.             TT(agg_M, T_LEAVE);
  1615.            // gefunden !
  1616.             return TRUE;
  1617.          }
  1618.       } 
  1619.    }   
  1620.    TT(agg_M,T_LEAVE);
  1621.       // nicht gefunden:
  1622.    return FALSE;
  1623. } // ** get_entry **
  1624.  
  1625. /*
  1626. Reihenfolge in der Hashtabelle:
  1627. Die Ordnung bezieht sich immer nur auf diejenigen Verweise in der Hashtabelle,
  1628. die die ersten Verweise auf eine bestimmte Seitenliste sind. Das Durchlaufen
  1629. mit einem Cursor funktioniert auf der Version mit list_cursor == FALSE so:
  1630. Die Cursor-Operatoren wurden ueberlagert, mit dem Oeffnen eines Cursors werden
  1631. die Prozeduren read_first_object und read_last_object aufgerufen, die das 
  1632. erste und letzte Objekt liefern. open_cursor setzt nun die Variablen 
  1633. first_object und last_object.  Beim Durchlaufen mit dem Cursor wird die 
  1634. Hashtabelle solange durchsucht, bis ein Verweis gefunden wird, der der Erste
  1635. auf die referenzierte Seitenliste ist. Dies ist der Fall, wenn in der Position
  1636. der Hashtabelle (ht_pos) nur die ersten (lokale_tiefe) Bit gesetzt sind. Auf 
  1637. der Seitenliste werden die Eintraege gemaess der Reihenfolge auf der Seite 
  1638. durchlaufen. Nach dem letzten Eintrag auf der Seitenliste beginnt wieder die
  1639. Suche in der Hashtabelle nach einem ersten Verweis auf die naechste 
  1640. Seitenliste.
  1641. */
  1642.  
  1643. // ************************************************************************** 
  1644. sos_Object get_pred ( sos_Container  ct,
  1645.                       sos_Bool       key_based_on_equal,
  1646.                       sos_Object     my_no_object,
  1647.                       sos_Int        ht_entries,
  1648.                       sos_Offset     ht_offset,
  1649.                       sos_Object     key)
  1650. // ************************************************************************** 
  1651. // Diese Prozedur wird nur aufgerufen, wenn get_list_cursor() == FALSE,
  1652. // d.h. die Version ohne verkettung der Eintraege ist gefragt.
  1653. // Es wird das Objekt in der eben geschilderten Reihenfolge nach key 
  1654. // geliefert.
  1655. {  sos_Int org_hash_value  =absolute((key_based_on_equal)?
  1656.                                       key.hash_value() : hash_id(key));
  1657.    sos_Int ht_pos = org_hash_value MOD ht_entries;
  1658.    sos_Object result;
  1659.  
  1660.    ht_entry_t ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1661.    page_t page;
  1662.    sos_Int first_link = FIRST_LINK(ht_pos, ht_entry.local_depth);
  1663.    ht_pos = first_link;
  1664.    sos_Offset page_offset = ht_entry.page_list_offset;
  1665.  
  1666.    page_header_t page_header = read_page_header (ct, page_offset);
  1667.    sos_Int pages = page_header.pages;
  1668.    sos_Int entries_on_last_page = page_header.entries_on_last_page;
  1669.    sos_Int entries_on_page = max_page_entries_without_list;
  1670.    result = my_no_object;
  1671.    sos_Int pos = -1; // entspricht "nicht gefunden"
  1672.    for (sos_Int page_no = 1;
  1673.         (page_no<=pages) AND (pos == -1);
  1674.         page_no++)
  1675.    {  if (page_no == pages)
  1676.      entries_on_page = entries_on_last_page;
  1677.  
  1678.       read_page(FALSE, ct, page_offset, entries_on_page, page);
  1679.       pos = search_page_for_key ( key_based_on_equal, page, entries_on_page,
  1680.                                   org_hash_value, key );
  1681.       if (pos == -1)
  1682.       {  page_offset = page.page_header.next_page;
  1683.          result = make_Object(page.entry[entries_on_page-1].key);
  1684.       }
  1685.       else
  1686.       {     // Findet sich der Vorgaenger auf derselben Seite ?
  1687.          if (pos > 0)
  1688.             result = make_Object(page.entry[pos-1].key);
  1689.          else
  1690.          {     // Falls eine vorherige Seite in der seitenliste
  1691.                // existiert, so wurde ihr letzter Eintrag in
  1692.                // result bereits gesetzt. Ist es jedoch die erste Seite
  1693.                // muss auf eine vorherige Seitenliste gegangen werden
  1694.             if (page_no == 1)
  1695.             {  sos_Bool found = FALSE;
  1696.                do
  1697.                {  ht_pos--;
  1698.                   do
  1699.                   {  if (ht_pos >= 0)
  1700.                      {     // suche den naechsten ersten verweis ab ht_pos;
  1701.                         ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1702.                         first_link = FIRST_LINK(ht_pos, ht_entry.local_depth);
  1703.  
  1704.                         if (first_link != ht_pos)
  1705.                            ht_pos--;
  1706.                       }
  1707.                   } while ((first_link != ht_pos) AND (ht_pos >= 0));
  1708.  
  1709.                   if (ht_pos >= 0)
  1710.                   {  page_header = 
  1711.                        read_page_header(ct,ht_entry.page_list_offset);
  1712.  
  1713.                         // Falls auf dieser Seitenliste ein
  1714.                         // Eintrag ist, lese ihn, sonst bleibt found == FALSE
  1715.                      if ((page_header.pages > 1) OR
  1716.                          (page_header.entries_on_last_page > 0))
  1717.                      {  found = TRUE;
  1718.                            // lese letzte Seite
  1719.                         sos_Int i = read_page(FALSE, ct,page_header, ht_entry,
  1720.                                           page_header.pages, page);
  1721.                         result = make_Object(page.entry[i-1].key);
  1722.                      }
  1723.                   }
  1724.                } while ((NOT found) AND (ht_pos >= 0));
  1725.             }
  1726.          }
  1727.       }
  1728.    } 
  1729.  
  1730.    return result;
  1731. } // ** get_pred **
  1732.  
  1733. // ************************************************************************** 
  1734. sos_Object get_succ ( sos_Container  ct,
  1735.                       sos_Bool       key_based_on_equal,
  1736.                       sos_Object     my_no_object,
  1737.                       sos_Int        ht_entries,
  1738.                       sos_Offset     ht_offset,
  1739.                       sos_Object     key)
  1740. // ************************************************************************** 
  1741. {  sos_Int org_hash_value = absolute((key_based_on_equal)?
  1742.                                      key.hash_value() : hash_id(key));
  1743.    sos_Int ht_pos = org_hash_value MOD ht_entries;
  1744.    sos_Object result;
  1745.  
  1746.    ht_entry_t ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1747.    page_t page;
  1748.    sos_Int first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
  1749.    ht_pos = first_link;
  1750.    sos_Offset page_offset = ht_entry.page_list_offset;
  1751.  
  1752.    page_header_t page_header = read_page_header (ct, page_offset);
  1753.    sos_Int pages = page_header.pages;
  1754.    sos_Int entries_on_last_page = page_header.entries_on_last_page;
  1755.    sos_Int entries_on_page = max_page_entries_without_list;
  1756.    result = my_no_object;
  1757.    sos_Int pos = -1; // entspricht "nicht gefunden"
  1758.    for (sos_Int page_no = 1; (page_no<=pages) AND (pos == -1); page_no++)
  1759.    {  if (page_no == pages)
  1760.      entries_on_page = entries_on_last_page;
  1761.  
  1762.       read_page(FALSE, ct, page_offset, entries_on_page, page);
  1763.       pos = search_page_for_key ( key_based_on_equal, page, entries_on_page,
  1764.                                   org_hash_value, key );
  1765.       if (pos == -1)
  1766.          page_offset = page.page_header.next_page;
  1767.       else
  1768.       {     // Findet sich der Nachfolger auf derselben Seite ?
  1769.          if (pos < entries_on_page-1)
  1770.             result = make_Object(page.entry[pos+1].key);
  1771.          else
  1772.          {  if (page_no < page_header.pages)
  1773.             {  read_page(FALSE, ct, page.page_header.next_page, 1, page);
  1774.                result = make_Object(page.entry[0].key);
  1775.             }
  1776.             else
  1777.             {     // Der Schluessel ist der letzte Eintrag auf der 
  1778.                   // Seitenliste, der Nachfolger ist auf der 
  1779.                   // naechsten Seitenliste
  1780.                sos_Bool found = FALSE;
  1781.                do
  1782.                {  ht_pos++;
  1783.                   do
  1784.                   {     // suche den naechsten ersten verweis ab ht_pos;
  1785.                         // read ht_entry
  1786.                      if (ht_pos < ht_entries)
  1787.                      {  ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1788.                         first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
  1789.                         if (first_link != ht_pos)
  1790.                            ht_pos++;
  1791.                      }
  1792.                    } while ((first_link != ht_pos) AND (ht_pos < ht_entries));
  1793.                       
  1794.                    if (ht_pos < ht_entries)
  1795.                    {     // lese den Seitenkopf und das erste 
  1796.                          // Objekt dieser Seite
  1797.                       read_page(FALSE,ct, ht_entry.page_list_offset, 1, page);
  1798.                       if ((page.page_header.pages > 1) OR
  1799.                           (page.page_header.entries_on_last_page > 0))
  1800.                       {  found = TRUE;
  1801.                          result = make_Object(page.entry[0].key);
  1802.                       }
  1803.                   }
  1804.                } while ((NOT found) AND (ht_pos < ht_entries));
  1805.             }
  1806.          }
  1807.       }
  1808.    } 
  1809.  
  1810.    return result;
  1811. } // ** Mapping::get_succ **
  1812.  
  1813.  
  1814. // ************************************************************************** 
  1815. sos_Object sos_Object_sos_Object_Mapping::search_succ_pred
  1816.                                              (sos_Object key, sos_Int steps)
  1817. // ************************************************************************** 
  1818. {  T_PROC("Mapping::search_succ_pred");
  1819.    TT(agg_M, T_ENTER; TI (steps));
  1820.  
  1821.    sos_Container ct             = self.container();
  1822.    sos_Bool key_based_on_equal  = self.get_key_based_on_equal();
  1823.    sos_Bool list_cursor         = self.get_list_cursor();
  1824.    sos_Object my_no_object      = self;
  1825.    sos_Int ht_entries           = self.get_ht_entries();
  1826.    sos_Offset ht_offset         = self.get_ht_offset();
  1827.    sos_Object dummy_info;  // wird in get_entry nicht angefasst
  1828.  
  1829.    for (;steps != 0;)
  1830.    {  sos_Object pred,succ;
  1831.       if (list_cursor)
  1832.       {  get_entry(ct, list_cursor, key_based_on_equal,
  1833.                    ht_entries,ht_offset, 
  1834.                    key, FALSE, dummy_info, pred,succ);
  1835.          if (steps > 0)
  1836.          {  if (succ == my_no_object)
  1837.         {  TT(agg_M, T_LEAVE);
  1838.                return my_no_object;
  1839.             }
  1840.             key = succ;
  1841.             steps--;
  1842.          }
  1843.          else
  1844.          {  if (pred == my_no_object)
  1845.         {  TT(agg_M, T_LEAVE);
  1846.                return my_no_object;
  1847.             }
  1848.             key = pred;
  1849.             steps++;
  1850.          }
  1851.       }
  1852.       else
  1853.       {  if (steps > 0)
  1854.          {  succ = get_succ(ct,key_based_on_equal,my_no_object,
  1855.                             ht_entries,ht_offset,key);
  1856.             if (succ == my_no_object)
  1857.         {  TT(agg_M, T_LEAVE);
  1858.                return my_no_object;
  1859.             } 
  1860.             key = succ;
  1861.             steps--;
  1862.          }
  1863.          else
  1864.          {  pred = get_pred(ct,key_based_on_equal,my_no_object,
  1865.                             ht_entries,ht_offset,key);
  1866.             if (pred == my_no_object)
  1867.             {  TT(agg_M, T_LEAVE);
  1868.            return my_no_object;
  1869.             }
  1870.             key = pred;
  1871.             steps++;
  1872.          }
  1873.       } 
  1874.    }
  1875.    TT(agg_M,T_LEAVE);
  1876.    return key;
  1877. } // ** Mapping::search_succ_pred **
  1878.  
  1879.  
  1880. // ************************************************************************** 
  1881. sos_Object read_last_object(sos_Container ct,
  1882.                             sos_Offset    ht_offset,
  1883.                             sos_Int       length,
  1884.                             sos_Object    my_no_object,
  1885.                             sos_Int       ht_entries)
  1886. // ************************************************************************** 
  1887. {  sos_Int ht_pos = ht_entries-1;
  1888.    sos_Bool found = FALSE;
  1889.    if (length == 0)
  1890.        return my_no_object;
  1891.    sos_Object result;
  1892.    ht_entry_t ht_entry;
  1893.    page_t page;
  1894.    page_header_t page_header;
  1895.    sos_Int first_link;
  1896.    do
  1897.    {  do
  1898.       {     // suche den vorherigen ersten Verweis ab ht_pos rueckwaerts
  1899.          ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1900.          first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
  1901.          if (first_link != ht_pos)
  1902.              ht_pos--;
  1903.       } while (first_link != ht_pos);
  1904.  
  1905.          // lese den page_header um festzustellen, ob auf der
  1906.          // Seitenliste ein Objekt ist
  1907.       page_header = read_page_header(ct,ht_entry.page_list_offset);
  1908.       if ((page_header.pages > 1) OR
  1909.           (page_header.entries_on_last_page > 0))
  1910.       {  found = TRUE;
  1911.             // lese letzte Seite
  1912.          read_page(FALSE,ct ,page_header, ht_entry, page_header.pages, page);
  1913.          result=make_Object(page.entry[page_header.entries_on_last_page-1].key);
  1914.       }
  1915.       else
  1916.          ht_pos--;
  1917.    } while (NOT found);
  1918.  
  1919.    return result;
  1920. } // ** Mapping::read_last_object **
  1921.  
  1922. // ************************************************************************** 
  1923. sos_Object read_first_object(sos_Container ct,
  1924.                              sos_Offset    ht_offset,
  1925.                              sos_Int       length,
  1926.                              sos_Object    my_no_object)
  1927. // ************************************************************************** 
  1928. {   sos_Int ht_pos = 0;
  1929.     sos_Bool found = FALSE;
  1930.     if (length == 0)
  1931.        return my_no_object;
  1932.     sos_Object result;
  1933.     ht_entry_t ht_entry;
  1934.     page_t page;
  1935.     sos_Int first_link;
  1936.  
  1937.     do
  1938.     {  do
  1939.        {     // suche den naechsten ersten verweis ab ht_pos;
  1940.              // read ht_entry
  1941.           ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1942.           first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
  1943.           if (first_link != ht_pos)
  1944.              ht_pos++;
  1945.        }
  1946.        while (first_link != ht_pos);
  1947.         
  1948.        // lese die Seite und das erste Objekt von diesem Verweis
  1949.        read_page(FALSE, ct, ht_entry.page_list_offset, 1, page);
  1950.        if ((page.page_header.pages > 1) OR
  1951.            (page.page_header.entries_on_last_page > 0))
  1952.        {  found = TRUE;
  1953.           result = make_Object(page.entry[0].key);
  1954.        }
  1955.        else
  1956.           ht_pos++;
  1957.     } while (NOT found);
  1958.     return result;
  1959. } // ** Mapping::read_first_object **
  1960.  
  1961.  
  1962. // ************************************************************************** 
  1963. void destroy_ht (sos_Bool       list_cursor,
  1964.                  sos_Container  ct, 
  1965.                  sos_Int        ht_entries, 
  1966.                  sos_Int        global_depth,
  1967.                  sos_Offset     ht_offset)
  1968. // ************************************************************************** 
  1969. {  T_PROC("destroy_ht ");
  1970.    TT (agg_M, T_ENTER; TI(ht_entries); TI(global_depth));
  1971.       // loescht alle Eintrage und die Hashtabelle,
  1972.  
  1973.    ht_entry_t ht_entry;
  1974.  
  1975.    for (sos_Int ht_pos=0;ht_pos < ht_entries;ht_pos++)
  1976.    {  ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  1977.       sos_Int local_depth = ht_entry.local_depth;
  1978.          // Berechne denjenigen Teil des Hashwertes, der auf der
  1979.          // Seitenliste unterschieden wird, dies ist gleichzeitig
  1980.          // der erste Verweis auf die Seitenliste
  1981.       sos_Int hash_value_part = FIRST_LINK(ht_pos, local_depth);
  1982.  
  1983.          // Berechne den letzten Verweis auf diese Seiteliste
  1984.       sos_Int last_link = LSHIFT(LSHIFT(1,global_depth-local_depth)-1,
  1985.                              local_depth) BITAND hash_value_part;
  1986.          // es muss der letzte Verweis sein, andernfalls wuerde die Kiste
  1987.          // beim nachfolgenden Lesen der lokalen Tiefe abschmieren,
  1988.          // da die Seite schon deallokiert waere.
  1989.  
  1990.          // Falls der gefundendene Verweis der letzte auf diese Seitenliste
  1991.          // ist, so deallokiere diese
  1992.       if (last_link == ht_pos) 
  1993.       {  page_header_t page_header = 
  1994.              read_page_header(ct,ht_entry.page_list_offset);
  1995.          destroy_page_list(list_cursor, ct,
  1996.                            ht_entry.page_list_offset, page_header.pages);
  1997.       }
  1998.    } 
  1999.  
  2000.    if (ht_entries>0)
  2001.       ct.deallocate(ht_offset,ht_entries*HT_ENTRY_SIZE);
  2002.  
  2003.    TT(agg_M,T_LEAVE);
  2004. } // ** Mapping::destroy_ht **
  2005.  
  2006. // ************************************************************************** 
  2007. void sos_Object_sos_Object_Mapping::init_table ()
  2008. // ************************************************************************** 
  2009. {  T_PROC("Mapping::init_table");
  2010.    TT(agg_H, T_ENTER);
  2011.  
  2012.       // create a hash-tab
  2013.       // Ein Eintrag besteht aus einem Offset
  2014.       // also einem Zeiger auf eine Seite
  2015.    self.set_ht_entries(1);
  2016.    sos_Container ct  = self.container();
  2017.    self.set_ht_offset(ct.allocate (self.get_ht_entries()*HT_ENTRY_SIZE)); 
  2018.  
  2019.       // no_of_pages[i] gibt an, wieviel Seiten mit der lokalen
  2020.       // Tiefe i existieren 
  2021.    self.set_no_of_pages_offset(ct.allocate(NO_OF_PAGES_ARRAY_SIZE));
  2022.    sos_Char mem [NO_OF_PAGES_ARRAY_SIZE];
  2023.    for (sos_Int i = 0;i< NO_OF_PAGES_ARRAY_SIZE;i++) mem[i] = 0;
  2024.    ct.write(self.get_no_of_pages_offset(), NO_OF_PAGES_ARRAY_SIZE, &mem);
  2025.  
  2026.    ht_entry_t ht_entry;
  2027.    ht_entry.page_list_offset = ct.allocate(PAGE_SIZE(self.get_list_cursor()));
  2028.    ht_entry.local_depth = 0;
  2029.    write_ht_entry(ct, self.get_ht_offset(),0,ht_entry);
  2030.  
  2031.    page_header_t page_header;
  2032.    page_header.pages = 1;
  2033.    page_header.entries_on_last_page = 0;
  2034.    write_page_header(ct,ht_entry.page_list_offset,page_header);
  2035.  
  2036.    self.set_no_of_pages(1);
  2037.    self.set_no_of_page_lists(1);
  2038.    add_no_of_pages(ct,self.get_no_of_pages_offset(),0,1);
  2039.  
  2040.    TT(agg_H,T_LEAVE);
  2041. } // ** Mapping::init_table **
  2042.  
  2043. // ************************************************************************** 
  2044. void sos_Object_sos_Object_Mapping::local_initialize
  2045.                                        (sos_Object_sos_Object_Mapping map)
  2046. // ************************************************************************** 
  2047. {  T_PROC("Mapping::local_initialize");
  2048.    TT(agg_H, T_ENTER);
  2049.  
  2050.    sos_Object my_no_object = map;
  2051.  
  2052.    map.set_cardinality (0);
  2053.    map.set_first_object(my_no_object); 
  2054.    map.set_last_object(my_no_object);
  2055.    map.set_ht_entries(0);
  2056.    map.set_global_depth(0);
  2057.    map.set_no_of_pages_offset(NIL);
  2058.    map.set_no_of_pages(0);
  2059.    map.set_ht_offset(NIL);
  2060.  
  2061.    TT(agg_H,T_LEAVE);
  2062. }; // ** Mapping::local_initialize **
  2063.  
  2064. // ************************************************************************** 
  2065. void sos_Object_sos_Object_Mapping::local_finalize
  2066.                                        (sos_Object_sos_Object_Mapping map)
  2067. // ************************************************************************** 
  2068. {  T_PROC("Mapping::local_finalize");
  2069.    TT (agg_H, T_ENTER);
  2070.  
  2071.    destroy_ht(map.get_list_cursor(), map.container(), map.get_ht_entries(), 
  2072.               map.get_global_depth(), map.get_ht_offset());
  2073.  
  2074.    TT (agg_H, T_LEAVE);
  2075. } // ** Mapping::local_finalize **
  2076.  
  2077. // ************************************************************************** 
  2078. sos_Bool sos_Object_sos_Object_Mapping::is_key (sos_Object key)
  2079. // ************************************************************************** 
  2080. {  T_PROC("Mapping::is_key");
  2081.    TT(agg_H, T_ENTER);
  2082.    sos_Object dummy_pred,dummy_succ,dummy_info;
  2083.    sos_Bool result = FALSE;
  2084.    sos_Object my_no_object = self;
  2085.    result = get_entry(self.container(), self.get_list_cursor(),  
  2086.                       self.get_key_based_on_equal(), 
  2087.                       self.get_ht_entries(), self.get_ht_offset(), 
  2088.                       key, FALSE, dummy_info, dummy_pred,dummy_succ);
  2089.    TT(agg_H, T_LEAVE);
  2090.    return result;
  2091. } // ** Mapping::is_key **
  2092.  
  2093.  
  2094. // ************************************************************************** 
  2095. sos_Bool sos_Object_sos_Object_Mapping::is_info (sos_Object info)
  2096. // ************************************************************************** 
  2097. // TRUE, falls info mit insert(*,info) in die Struktur
  2098. // aufgenommen wurde.
  2099. // Vorsicht !! nicht aufrufen !!
  2100. // Die Funktion hat einen Aufwand von o(Anzahl der Eintraege) !!
  2101. {  T_PROC("Mapping::is_info");
  2102.    TT(agg_H,T_ENTER);
  2103.  
  2104.    sos_Container  ct = self.container(); 
  2105.    sos_Bool       list_cursor = self.get_list_cursor();
  2106.    sos_Bool       info_based_on_equal = self.get_info_based_on_equal();
  2107.    ht_entry_t  ht_entry;
  2108.    page_t      page;
  2109.    sos_Object  key;
  2110.  
  2111.       // Durchlaufe die gesamte Hashtabelle
  2112.       // benutze jeden Verweis um die Seite zu durchsuchen,
  2113.       // verwende bei mehrfachen Verweisen nur den ersten
  2114.    sos_Int ht_entries = self.get_ht_entries();
  2115.    sos_Offset ht_offset = self.get_ht_offset();
  2116.    for (sos_Int ht_pos=0;
  2117.         ht_pos < ht_entries; // positiver Abbruch nur in der Schleife
  2118.         ht_pos++)
  2119.    {  ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
  2120.    
  2121.          // Wie lautet der dieser Seite zugeordnete Hash-Wert ?
  2122.       sos_Int hash_value_part = (LSHIFT(1,ht_entry.local_depth)-1) 
  2123.                                 BITAND ht_pos;
  2124.    
  2125.          // Ist dieser Verweis der erste auf diese Seite ?
  2126.       if (hash_value_part == ht_pos)
  2127.       {     // Ja, 
  2128.          sos_Offset page_offset = ht_entry.page_list_offset;
  2129.          page_header_t page_header = read_page_header(ct, page_offset);
  2130.    
  2131.          sos_Bool found = FALSE;
  2132.          sos_Int pages = page_header.pages;
  2133.      sos_Int entries_on_last_page = page_header.entries_on_last_page;
  2134.      sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
  2135.          for (sos_Int page_no = 1;
  2136.               (page_no<=pages) AND (NOT found);
  2137.               page_no++)
  2138.          {  if (page_no == pages)
  2139.            entries_on_page = entries_on_last_page;
  2140.                 
  2141.             if (entries_on_page > 0)
  2142.                read_page(list_cursor, ct,page_offset, 
  2143.                          entries_on_page, page);
  2144.                
  2145.                // Durchsuche die Seite nach dem Objekt
  2146.             for (sos_Int k=0; 
  2147.                  (NOT found) AND (k<entries_on_page); 
  2148.                  k++)
  2149.             {  key = make_Object(page.entry[k].info);
  2150.                found = agg_same_entity (key,info,info_based_on_equal,EQ_STRONG); 
  2151.         } 
  2152.    
  2153.             if (found) 
  2154.             {  TT(agg_H,T_LEAVE);
  2155.                return TRUE; 
  2156.             } 
  2157.    
  2158.             page_offset = page.page_header.next_page;
  2159.          } 
  2160.       }
  2161.    } 
  2162.  
  2163.    TT(agg_H,T_LEAVE);
  2164.    return FALSE; // Pech ...
  2165. } // ** Mapping::is_info **
  2166.  
  2167. // ************************************************************************** 
  2168. void sos_Object_sos_Object_Mapping::insert(sos_Object Key, sos_Object Entity)
  2169. // ************************************************************************** 
  2170. {  T_PROC("Mapping::insert");
  2171.    TT(agg_H, T_ENTER);
  2172.  
  2173.    sos_Object my_no_object = self;
  2174.       // Das Mappingobjekt selbst wird als Methodenausgabe fuer ein ungueltiges 
  2175.       // Objekt benutzt. Drum kann man NO_OBJECT, aber nicht das
  2176.       // Mappingobjekt einfuegen. Soll es auch auch eingefuegt werden koennen, 
  2177.       // benoetigt man ein eigenes MAPPING_NO_OBJECT.
  2178.    if (Key == self)
  2179.       err_raise(err_USE,"Mapping itself cannot inserted","Mapping::insert");
  2180.  
  2181.       // fuege das Element in der Listen-Version hinten an die Liste
  2182.       // in der non-Listen Version haben die beiden letzten Parameter
  2183.       // pred und succ keine Wirkung
  2184.    self.insert_in_list(Key, Entity, self.get_last_object(), my_no_object);
  2185.  
  2186.    TT(agg_H,T_LEAVE);   
  2187. } // ** Mapping::insert **
  2188.  
  2189. // ************************************************************************** 
  2190. void sos_Object_sos_Object_Mapping::remove (sos_Object key)
  2191. // ************************************************************************** 
  2192. {  T_PROC("Mapping::remove");
  2193.  
  2194.    sos_Bool found=FALSE;
  2195.  
  2196.    if (self.get_ht_entries() >0)
  2197.    {  sos_Container ct = self.container(); 
  2198.       sos_Int org_hash_value = absolute((self.get_key_based_on_equal())?
  2199.                                         key.hash_value():hash_id(key));
  2200.       sos_Int ht_pos         = org_hash_value MOD self.get_ht_entries();
  2201.       ht_entry_t ht_entry = read_ht_entry(ct,self.get_ht_offset(),ht_pos);
  2202.       found = make_sos_Bool(
  2203.       self.remove_from_page_list (ct, self.get_list_cursor(),
  2204.                               self.get_key_based_on_equal(),
  2205.                               ht_entry.page_list_offset, 
  2206.                                   org_hash_value,key));
  2207.       sos_Object my_no_object = self;
  2208.       if (found)
  2209.       {     // Versuche, die Seitenliste zu verschmelzen
  2210.          if (self.assemble_page(ht_entry.page_list_offset, 
  2211.                                 ht_entry.local_depth, 
  2212.                                 org_hash_value))
  2213.                // versuche, die Hash-Tabelle zu verkleinern
  2214.             self.decrease_hash_table();
  2215.       }
  2216.    } 
  2217.    TT(agg_H,T_LEAVE; TB(found));
  2218. }// ** Mapping::remove **
  2219.  
  2220. // ************************************************************************** 
  2221. sos_Object sos_Object_sos_Object_Mapping::operator[] (sos_Object key)
  2222. // ************************************************************************** 
  2223. {  T_PROC("Mapping::operator[]");
  2224.    TT(agg_H,T_ENTER);
  2225.  
  2226.    sos_Object dummy_pred,dummy_succ,info;
  2227.    sos_Container  ct = self.container();
  2228.    sos_Bool       key_based_on_equal = self.get_key_based_on_equal();
  2229.    sos_Bool       list_cursor = self.get_list_cursor();
  2230.    sos_Object     my_no_object = self;
  2231.    sos_Int        ht_entries = self.get_ht_entries();
  2232.    sos_Offset     ht_offset = self.get_ht_offset();
  2233.  
  2234.    if (NOT get_entry(ct, list_cursor,key_based_on_equal,ht_entries,
  2235.              ht_offset,key,TRUE, info, dummy_pred,dummy_succ))
  2236.       info = NO_OBJECT;
  2237.  
  2238.    TT(agg_H,T_LEAVE);
  2239.    return info;
  2240. } // ** Mapping::operator[] **
  2241.  
  2242. // ************************************************************************** 
  2243. sos_Object sos_Object_sos_Object_Mapping::get_key(sos_Cursor c)
  2244. // ************************************************************************** 
  2245. {  T_PROC("Mapping::get_key(sos_Cursor)");
  2246.    TT(agg_H, T_ENTER);
  2247.  
  2248.    err_assert (c.defined_for (self), "Mapping:get_key");
  2249.    err_assert (self.is_valid(c), "Mapping:get_key");
  2250.  
  2251.    sos_Map_node mn = sos_Map_node::make (c.get_current());
  2252.    sos_Object   o  = mn.get_key_val();
  2253.  
  2254.    TT(agg_H,T_LEAVE);
  2255.    return o;
  2256. } // ** Mapping::get_key **
  2257.  
  2258. // ************************************************************************** 
  2259. sos_Object sos_Object_sos_Object_Mapping::get_info(sos_Cursor c)
  2260. // ************************************************************************** 
  2261. {  T_PROC("Mapping::get_info(sos_Cursor)");
  2262.    TT(agg_H, T_ENTER);
  2263.  
  2264.    err_assert (c.defined_for (self), "Mapping:get_info");
  2265.    err_assert(self.is_valid(c),"Mapping:get_info");
  2266.  
  2267.    sos_Object my_no_object = self;
  2268.    sos_Object dummy_pred,
  2269.           dummy_succ;
  2270.  
  2271.    sos_Object key = sos_Map_node::make (c.get_current()).get_key_val();
  2272.    sos_Object info;
  2273.    sos_Bool found = get_entry(self.container(), self.get_list_cursor(),
  2274.                               self.get_key_based_on_equal(),
  2275.                               self.get_ht_entries(), self.get_ht_offset(), 
  2276.                               key,TRUE, info,dummy_pred,dummy_succ);
  2277.       // Beliebter Benutzerfehler: Ein Prozess erzeugt
  2278.       // einen Eintrag mit einem Key im TEMP_CONTAINER, das
  2279.       // Programm beendet, ein anderer Prozess versucht darueber
  2280.       // zu itterieren. Trotz das im Key Bockmist steht, kann er
  2281.       // noch mit get_key geliefert werden. Wenn jedoch der passende Eintrag 
  2282.       // dazu gesucht wird, wird der Hashwert vom Key gebraucht. In diesem
  2283.       // stehen wilde Sachen, der Eintrag wird (vermutlich) nicht gefunden.
  2284.    if (NOT found)
  2285.       err_raise(err_USE,"Entry didn't exists anymore","Mapping::get_info");
  2286.  
  2287.    TT(agg_H, T_LEAVE);
  2288.    return info;
  2289. } // ** Mapping::get_info **
  2290.  
  2291. // ************************************************************************** 
  2292. void sos_Object_sos_Object_Mapping::set_info(sos_Cursor c, sos_Object o)
  2293. // ************************************************************************** 
  2294. {  T_PROC ("Mapping::set_info");
  2295.    TT (agg_H, T_ENTER);
  2296.  
  2297.    err_assert ((c.defined_for (self)), "Mapping:set_info");
  2298.    self.insert (sos_Map_node::make (c.get_current()).get_key_val(), o);
  2299.  
  2300.    TT (agg_H, T_LEAVE);
  2301. } // ** Mapping::set_info **
  2302.  
  2303. // ************************************************************************** 
  2304. void sos_Object_sos_Object_Mapping::move_cursor(sos_Cursor c, sos_Object key)
  2305. // ************************************************************************** 
  2306. // sets the cursor c to the key object in the mapping that corresponds
  2307. // to the given key
  2308. {  T_PROC ("Mapping::move_cursor");
  2309.    TT( agg_H, T_ENTER);
  2310.  
  2311.    err_assert (c.defined_for (self), "Mapping:move_cursor");
  2312.    err_assert (self.is_key(key), "Mapping:move_cursor");
  2313.  
  2314.    sos_Object dummy_pred, dummy_succ, dummy_info;
  2315.    sos_Bool found = get_entry(self.container(), self.get_list_cursor(),
  2316.                               self.get_key_based_on_equal(),
  2317.                               self.get_ht_entries(),self.get_ht_offset(),
  2318.                               key,FALSE, dummy_info, dummy_pred,dummy_succ);
  2319.    err_assert (found, "Mapping:move_cursor");
  2320.    sos_Map_node::make (c.get_current()).set_key_val(key); 
  2321.  
  2322.    TT(agg_H, T_LEAVE);
  2323. } // ** Mapping::move_cursor **
  2324.  
  2325. // ************************************************************************** 
  2326. void sos_Object_sos_Object_Mapping::insert_before (sos_Cursor c,
  2327.                                                    sos_Object Key,
  2328.                                                    sos_Object Entity)
  2329. // ************************************************************************** 
  2330. {  T_PROC("Mapping::insert_before");
  2331.    TT(agg_H, T_ENTER);
  2332.  
  2333.    err_assert (self.get_list_cursor(), "Mapping:insert_before");
  2334.    err_assert (c.defined_for (self), "Mapping:insert_before");
  2335.    err_assert (self.is_valid(c), "Mapping:insert_before");
  2336.  
  2337.    if (Key == self)
  2338.       err_raise(err_USE,"Mapping itself cannot inserted","Mapping::insert");
  2339.    sos_Map_node mn = sos_Map_node::make (c.get_current());
  2340.  
  2341.    sos_Object dummy_info,pred,dummy_succ;
  2342.    sos_Object key = mn.get_key_val();
  2343.    get_entry(self.container(), self.get_list_cursor(), 
  2344.              self.get_key_based_on_equal(),
  2345.              self.get_ht_entries(),self.get_ht_offset(),
  2346.              key,FALSE, dummy_info, pred,dummy_succ);
  2347.    self.insert_in_list(Key, Entity, pred, mn.get_key_val());
  2348.  
  2349.    TT(agg_H, T_LEAVE);
  2350. } // ** Mapping::insert_before **
  2351.  
  2352. // ************************************************************************** 
  2353. void sos_Object_sos_Object_Mapping::insert_after (sos_Cursor c,
  2354.                                                   sos_Object Key,
  2355.                                                   sos_Object Entity)
  2356. // ************************************************************************** 
  2357. {  T_PROC("Mapping::insert_after");
  2358.    TT(agg_H, T_ENTER);
  2359.  
  2360.    err_assert (self.get_list_cursor(), "Mapping:insert_after");
  2361.    err_assert (c.defined_for (self), "Mapping:insert_after");
  2362.    err_assert (self.is_valid(c), "Mapping:insert_after");
  2363.  
  2364.    if (Key == self)
  2365.       err_raise(err_USE,"Mapping itself cannot inserted","Mapping::insert");
  2366.  
  2367.    sos_Map_node mn = sos_Map_node::make (c.get_current());
  2368.  
  2369.    sos_Object dummy_info,dummy_pred,succ;
  2370.    sos_Object key = mn.get_key_val();
  2371.    get_entry(self.container(), self.get_list_cursor(), 
  2372.              self.get_key_based_on_equal(),
  2373.              self.get_ht_entries(),self.get_ht_offset(),
  2374.              key,FALSE,dummy_info,dummy_pred,succ);
  2375.    self.insert_in_list(Key, Entity, mn.get_key_val(), succ);
  2376.  
  2377.    TT(agg_H, T_LEAVE);
  2378. } // ** Mapping::insert_after **
  2379.  
  2380. // ************************************************************************** 
  2381. void sos_Object_sos_Object_Mapping::local_assign
  2382.                                        (sos_Object_sos_Object_Mapping x,
  2383.                                         sos_Object                    o)
  2384. // ************************************************************************** 
  2385. {  T_PROC("Mapping::local_assign");
  2386.  
  2387.    sos_Object_sos_Object_Mapping y = sos_Object_sos_Object_Mapping::make (o);
  2388.    sos_Container y_ct = y.container();
  2389.    sos_Container x_ct = x.container();
  2390.    sos_Bool x_list_cursor = x.get_list_cursor();
  2391.    
  2392.    err_assert ((y.get_list_cursor() == x_list_cursor),
  2393.                "Mapping::local_assign");
  2394.  
  2395.    destroy_ht(x_list_cursor, x_ct, x.get_ht_entries(),
  2396.               x.get_global_depth(), x.get_ht_offset());
  2397.  
  2398.    sos_Bool key_based_on_equal = y.get_key_based_on_equal();
  2399.    sos_Bool info_based_on_equal= y.get_info_based_on_equal();
  2400.    sos_Int cardinality         = y.get_cardinality();
  2401.    sos_Int no_of_pages         = y.get_no_of_pages();
  2402.    sos_Int no_of_page_lists    = y.get_no_of_page_lists();
  2403.    sos_Int global_depth        = y.get_global_depth();
  2404.    sos_Int ht_entries          = y.get_ht_entries();
  2405.    sos_Int no_of_pages_offset  = y.get_no_of_pages_offset();
  2406.  
  2407.    x.set_key_based_on_equal(key_based_on_equal);
  2408.    x.set_info_based_on_equal(info_based_on_equal);
  2409.    x.set_cardinality(cardinality);
  2410.    x.set_no_of_pages(no_of_pages);
  2411.    x.set_no_of_page_lists(no_of_page_lists);
  2412.    x.set_global_depth(global_depth);
  2413.    x.set_ht_entries(ht_entries);
  2414.    x.set_first_object(y.get_first_object());
  2415.    x.set_last_object(y.get_last_object());
  2416.  
  2417.  
  2418.    if (cardinality != 0)
  2419.    {    // kopiere das Feld fuer no_of_pages rueber
  2420.       sos_Offset new_no_of_pages_offset = x_ct.allocate(NO_OF_PAGES_ARRAY_SIZE);
  2421.       x.set_no_of_pages_offset(new_no_of_pages_offset);
  2422.       sos_Char mem [NO_OF_PAGES_ARRAY_SIZE];
  2423.       y_ct.read(no_of_pages_offset, NO_OF_PAGES_ARRAY_SIZE, &mem);
  2424.       x_ct.write(new_no_of_pages_offset, NO_OF_PAGES_ARRAY_SIZE, &mem);
  2425.   
  2426.          // erzeuge die Hashtabelle
  2427.       x.set_ht_offset(x_ct.allocate(y.get_ht_entries() *HT_ENTRY_SIZE));
  2428.          // Laufe die erste HT durch und kopiere die Seiten
  2429.       sos_Offset old_ht_offset = y.get_ht_offset();
  2430.       sos_Offset new_ht_offset = x.get_ht_offset();
  2431.       for (sos_Int ht_pos = 0;ht_pos<y.get_ht_entries();ht_pos++)
  2432.       {  ht_entry_t ht_entry = read_ht_entry(y_ct,old_ht_offset,ht_pos);
  2433.    
  2434.             // Ist es der erste Zeiger auf die Seitenliste ?
  2435.          sos_Int local_depth = ht_entry.local_depth;
  2436.          sos_Int first_link = FIRST_LINK(ht_pos, local_depth);
  2437.          if (first_link == ht_pos)
  2438.          {     // erster Verweis, kopiere die Seitenliste
  2439.             sos_Offset old_page_offset = ht_entry.page_list_offset;
  2440.             page_header_t  old_first_page_header = 
  2441.                 read_page_header(y_ct, ht_entry.page_list_offset);
  2442.    
  2443.             sos_Offset pred_page_offset=0;
  2444.    
  2445.             for(sos_Int page_no=1;page_no<=old_first_page_header.pages;page_no++)
  2446.             {  sos_Offset new_page_offset = 
  2447.           x_ct.allocate(PAGE_SIZE(x_list_cursor));
  2448.                if (page_no == 1)
  2449.                   ht_entry.page_list_offset = new_page_offset;
  2450.                else
  2451.                {  page_header_t tmp_page_header = old_first_page_header;
  2452.                   tmp_page_header.next_page = new_page_offset;
  2453.                   // schreibe den Seitenverweis in den Vorgaenger
  2454.                   write_page_header(x_ct,pred_page_offset, tmp_page_header);
  2455.                }
  2456.    
  2457.                page_t tmp_page;
  2458.                sos_Int entries = (page_no < old_first_page_header.pages)?
  2459.                                  MAX_PAGE_ENTRIES(x_list_cursor):
  2460.                                  old_first_page_header.entries_on_last_page;
  2461.  
  2462.                   // kopiere die Seite
  2463.                read_page(x_list_cursor,y_ct,old_page_offset,entries,tmp_page);
  2464.                write_page(x_list_cursor, x_ct,new_page_offset,
  2465.                           MAX_PAGE_ENTRIES(x_list_cursor), tmp_page);
  2466.                pred_page_offset = new_page_offset;
  2467.    
  2468.                   // lese den Seitenkopf der Seite, um 
  2469.           // Nachfolgerseite rauszufinden
  2470.                page_header_t old_page_header = 
  2471.                   read_page_header(y_ct,old_page_offset);
  2472.                
  2473.                old_page_offset = old_page_header.next_page;
  2474.             } // kopiere alle Seiten
  2475.    
  2476.                // schreibe den HT-Eintrag in alle Verweise der HT
  2477.             sos_Int no_of_links = LSHIFT(1,global_depth-local_depth);
  2478.             for (sos_Int k=0;k<no_of_links;k++)
  2479.             {  sos_Int x = LSHIFT(k,local_depth);
  2480.                sos_Int other_link = x BITOR ht_pos;
  2481.                write_ht_entry(x_ct,new_ht_offset,other_link,ht_entry);
  2482.             } // schreibe alle HT-Eintraege pro Seite
  2483.          } 
  2484.       } 
  2485.       if (x_list_cursor)
  2486.       {  sos_Object my_no_object = x;
  2487.          x.write_succ_pred
  2488.             (x_ct, key_based_on_equal, x_list_cursor, 
  2489.              x.get_first_object(), FALSE, my_no_object);
  2490.          x.write_succ_pred
  2491.             (x_ct, key_based_on_equal, x_list_cursor,  
  2492.              x.get_last_object(), TRUE, my_no_object);
  2493.       }
  2494.    }
  2495.    else
  2496.    {     // Kein Element drin, erzeuge nichts, initialisere wie in local_init
  2497.       sos_Object my_no_object = x;
  2498.       x.set_first_object(my_no_object);
  2499.       x.set_last_object(my_no_object);
  2500.       x.set_ht_offset(NIL);
  2501.       x.set_ht_entries(0);
  2502.       x.set_no_of_pages_offset(NIL);
  2503.    }
  2504.  
  2505.    TT(agg_H,T_LEAVE); 
  2506. } // ** Mapping::local_assign **
  2507.  
  2508. // ************************************************************************** 
  2509. sos_Bool sos_Object_sos_Object_Mapping::local_equal
  2510.                                        (sos_Object_sos_Object_Mapping x,
  2511.                                         sos_Object                    o,
  2512.                                         sos_Eq_kind                   eq_kind) 
  2513. // ************************************************************************** 
  2514. {  sos_Bool result;
  2515.  
  2516.    if ((eq_kind EQ EQ_STRONG AND NOT o.has_type(x.type())) OR
  2517.        (eq_kind EQ EQ_WEAK   AND NOT o.isa     (x.type())))
  2518.       result = FALSE;
  2519.    else
  2520.    {  sos_Object_sos_Object_Mapping y = 
  2521.          sos_Object_sos_Object_Mapping::make (o);
  2522.       if (y.get_cardinality() != x.get_cardinality())
  2523.          result = FALSE; 
  2524.       else
  2525.       {  sos_Bool info_based_on_equal = x.get_info_based_on_equal();
  2526.          agg_iterate_association (x, sos_Object key, sos_Object info)
  2527.          {  if (NOT agg_same_entity (y[key],info,info_based_on_equal,eq_kind))
  2528.             {  result = FALSE;
  2529.                break;
  2530.             }
  2531.          } 
  2532.          agg_iterate_association_end (x, key, info);
  2533.       }
  2534.    }
  2535.  
  2536.    return result;
  2537. } // ** Mapping::local_equal **
  2538.  
  2539. // ************************************************************************** 
  2540. sos_Int sos_Object_sos_Object_Mapping::local_hash_value
  2541.                                        (sos_Object_sos_Object_Mapping m)
  2542. // ************************************************************************** 
  2543. // Ansich muesste der augenblickliche Hashwert gespeichert werden, und bei 
  2544. // jedem eingefuegten Element mit einer reversiblen Operation verknuepft 
  2545. // werden. Bei jedem remove, muss diese reversible Operation aufgerufen 
  2546. // werden. Zu viel Aufwand, drum bisher noch nicht implementiert.
  2547. {  return m.card();
  2548. } // ** Mapping::local_hash_value **
  2549.  
  2550. // ************************************************************************** 
  2551. sos_Int sos_Object_sos_Object_Mapping::size()
  2552. // ************************************************************************** 
  2553. {  sos_Int o_size = sos_Object::size();
  2554.    sos_Int ht_size = self.get_ht_entries() * HT_ENTRY_SIZE;
  2555.    sos_Int nop_size = (ht_size>0)?NO_OF_PAGES_ARRAY_SIZE:0;
  2556.    sos_Int pg_size = self.get_no_of_pages()*PAGE_SIZE(self.get_list_cursor());
  2557.    return o_size +
  2558.           self.container().rounded (ht_size) +
  2559.           self.container().rounded (pg_size) +
  2560.           self.container().rounded (nop_size);
  2561. } // ** Mapping::size **
  2562.  
  2563. // **************************************************************************
  2564. sos_Bool sos_Object_sos_Object_Mapping::is_role1 (sos_Object key)
  2565. // **************************************************************************
  2566. {  return self.is_key (key);
  2567. } // ** Mapping::is_role1 **
  2568.  
  2569. // **************************************************************************
  2570. sos_Bool sos_Object_sos_Object_Mapping::is_role2 (sos_Object info)
  2571. // **************************************************************************
  2572. {  return self.is_info (info);
  2573. } // ** Mapping::is_role2 **
  2574.  
  2575. // **************************************************************************
  2576. sos_Object sos_Object_sos_Object_Mapping::get_role1 (sos_Cursor c)
  2577. // **************************************************************************
  2578. {  return self.get_key (c);
  2579. } // ** Mapping::get_role1 **
  2580.  
  2581. // **************************************************************************
  2582. sos_Object sos_Object_sos_Object_Mapping::get_role2 (sos_Cursor c)
  2583. // **************************************************************************
  2584. {  return self.get_info (c);
  2585. } // ** Mapping::get_role2 **
  2586.  
  2587. // ************************************************************************** 
  2588. void sos_Object_sos_Object_Mapping::remove_at(sos_Cursor c)
  2589. // ************************************************************************** 
  2590. {  T_PROC("Mapping::remove_at");
  2591.    TT(agg_H, T_ENTER);
  2592.  
  2593.    err_assert (c.defined_for (self), "Mapping:remove_at");
  2594.    err_assert (self.is_valid(c), "Mapping:remove_at");
  2595.  
  2596.    sos_Object key = self.get_key(c);
  2597.  
  2598.    if (self.get_list_cursor())
  2599.       self.to_succ(c);
  2600.    else
  2601.    {     // Setze Cursor auf my_no_object => is_valid == FALSE
  2602.       sos_Object my_no_object = self;
  2603.       sos_Map_node mn = sos_Map_node::make (c.get_current());
  2604.       mn.set_key_val(my_no_object);
  2605.    }
  2606.  
  2607.    self.remove(key);
  2608.  
  2609.    TT(agg_H, T_LEAVE);
  2610. } // ** Mapping::remove_at **
  2611.  
  2612. // ************************************************************************** 
  2613. void sos_Object_sos_Object_Mapping::clear()
  2614. // ************************************************************************** 
  2615. {  T_PROC("Mapping::clear");
  2616.    TT(agg_H, T_ENTER);
  2617.    
  2618.    sos_Container ct = self.container();
  2619.    sos_Int ht_entries = self.get_ht_entries();
  2620.    if (ht_entries >0)
  2621.       destroy_ht(self.get_list_cursor(), ct, ht_entries,
  2622.                  self.get_global_depth(), self.get_ht_offset());
  2623.  
  2624.    sos_Object my_no_object = self;
  2625.    self.set_first_object(my_no_object);
  2626.    self.set_last_object(my_no_object);
  2627.    self.set_cardinality (0);
  2628.    self.set_ht_entries(0);
  2629.    self.set_global_depth(0);
  2630.    self.set_no_of_pages_offset(NIL);
  2631.    self.set_no_of_pages(0);
  2632.    self.set_ht_offset(NIL);
  2633.  
  2634.    TT(agg_H, T_LEAVE);
  2635. } // ** Mapping::clear **
  2636.  
  2637. // **************************************************************************
  2638. sos_Int sos_Object_sos_Object_Mapping::card ()
  2639. // **************************************************************************
  2640. {  T_PROC ("Mapping::card");
  2641.    TT (agg_H, T_ENTER);
  2642.  
  2643.    sos_Int crd = self.get_cardinality();
  2644.  
  2645.    TT (agg_H, T_LEAVE);
  2646.    return crd;
  2647. } // ** Mapping::card **
  2648.  
  2649. // ************************************************************************** 
  2650. sos_Cursor sos_Object_sos_Object_Mapping::open_cursor(sos_Container Cursor_ct)
  2651. // ************************************************************************** 
  2652. {  T_PROC ("Mapping::open_cursor");
  2653.    TT( agg_H, T_ENTER);
  2654.  
  2655.    sos_Cursor c = sos_Cursor::create(Cursor_ct, self);
  2656.    sos_Map_node mn = sos_Map_node::create(Cursor_ct);
  2657.    c.set_current(mn);
  2658.  
  2659.    self.to_first(c);
  2660.  
  2661.    TT(agg_H, T_LEAVE);
  2662.    return c;
  2663. } // ** Mapping::open_cursor **
  2664.  
  2665. // ************************************************************************** 
  2666. void sos_Object_sos_Object_Mapping::close_cursor(sos_Cursor c)
  2667. // ************************************************************************** 
  2668. {  err_assert ((c.defined_for (self)), "Mapping:close_cursor");
  2669.    c.get_current().destroy(); 
  2670.    c.destroy(); 
  2671. } // ** Mapping::close_cursor **
  2672.  
  2673. // ************************************************************************** 
  2674. sos_Cursor sos_Object_sos_Object_Mapping::duplicate(sos_Cursor c)
  2675. // ************************************************************************** 
  2676. {  err_assert ((c.defined_for (self)), "Mapping:duplicate");
  2677.    sos_Container Cursor_ct = c.container();
  2678.  
  2679.    sos_Cursor dup_c = sos_Cursor::create(Cursor_ct, self);
  2680.    sos_Map_node dup_mn = sos_Map_node::create(Cursor_ct);
  2681.  
  2682.    dup_c.set_current (dup_mn);
  2683.    dup_mn.set_key_val (sos_Map_node::make (c.get_current()).get_key_val());
  2684.  
  2685.    return dup_c;
  2686. } // ** Mapping::duplicate **
  2687.  
  2688. // **************************************************************************
  2689. sos_Bool sos_Object_sos_Object_Mapping::is_valid (sos_Cursor c)
  2690. // **************************************************************************
  2691. {  sos_Map_node mn           = sos_Map_node::make (c.get_current());
  2692.    sos_Object   my_no_object = self;
  2693.    sos_Bool     valid        = (mn.get_key_val() != my_no_object);
  2694.  
  2695.    return valid;
  2696. } // ** is_valid **
  2697.  
  2698. // ************************************************************************** 
  2699. sos_Bool sos_Object_sos_Object_Mapping::to_first(sos_Cursor c)
  2700. // ************************************************************************** 
  2701. {  err_assert ((c.defined_for (self)), "Mapping:to_first");
  2702.    sos_Container Cursor_ct = c.container();
  2703.    sos_Map_node  current = sos_Map_node::make (c.get_current());
  2704.    sos_Object    my_no_object = self;
  2705.    sos_Object    first;
  2706.  
  2707.    if (self.get_cardinality() > 0)
  2708.    {  if (NOT (self.get_list_cursor()))
  2709.          first = read_first_object(self.container(),self.get_ht_offset(),
  2710.                                    self.get_cardinality(),my_no_object);
  2711.       else
  2712.          first = self.get_first_object();
  2713.    }
  2714.    else
  2715.       first = my_no_object;
  2716.    
  2717.    current.set_key_val(first);
  2718.  
  2719.    return self.is_valid(c);
  2720. } // ** Mapping::to_first **
  2721.  
  2722. // ************************************************************************** 
  2723. sos_Bool sos_Object_sos_Object_Mapping::to_last(sos_Cursor c)
  2724. // ************************************************************************** 
  2725. {  err_assert ((c.defined_for (self)), "Mapping:to_last");
  2726.    sos_Map_node  current      = sos_Map_node::make (c.get_current());
  2727.    sos_Container Cursor_ct    = c.container();
  2728.    sos_Object    my_no_object = self;
  2729.    sos_Object    last;
  2730.  
  2731.    if (self.get_cardinality() > 0)
  2732.    {  if (NOT (self.get_list_cursor()))
  2733.          last = read_last_object
  2734.                    (self.container(),
  2735.                     self.get_ht_offset(),self.get_cardinality(),
  2736.                     my_no_object,self.get_ht_entries());
  2737.       else
  2738.          last = self.get_last_object();
  2739.    }      
  2740.    else
  2741.       last = my_no_object;
  2742.  
  2743.    current.set_key_val(last);
  2744.  
  2745.    return self.is_valid(c);
  2746. } // ** Mapping::to_last **
  2747.  
  2748. // ************************************************************************** 
  2749. sos_Bool sos_Object_sos_Object_Mapping::to_succ(sos_Cursor c, Index i) 
  2750. // ************************************************************************** 
  2751. {  err_assert (c.defined_for (self), "Mapping:to_succ");
  2752.    err_assert (self.is_valid(c), "Mapping:to_succ");
  2753.  
  2754.    sos_Map_node mn = sos_Map_node::make (c.get_current());
  2755.    sos_Object   o  = self.search_succ_pred (mn.get_key_val(),i);
  2756.  
  2757.    mn.set_key_val (o); 
  2758.  
  2759.    return self.is_valid (c);
  2760. } // ** Mapping::to_succ **
  2761.  
  2762. // ************************************************************************** 
  2763. sos_Bool sos_Object_sos_Object_Mapping::to_pred(sos_Cursor c, Index i)
  2764. // ************************************************************************** 
  2765. {  return self.to_succ(c,-i); 
  2766. } // ** Mapping::to_pred **
  2767.